What is the fastest way to check if a class has a specific function?

I am writing an AI state space search algorithm, and I have a general class that can be used to quickly implement a search algorithm. The subclass will determine the necessary operations, and the algorithm will do the rest.

This is where I am stuck: I want to restore the parent state again and again, so I have the following function that returns operations that can be legally applied to any state:

def get_operations(self, include_parent=True): ops = self._get_operations() if not include_parent and self.path.parent_op: try: parent_inverse = self.invert_op(self.path.parent_op) ops.remove(parent_inverse) except NotImplementedError: pass return ops 

And the invert_op function is thrown by default.

Is there a faster way to check if a function is defined, moreover, how to catch an exception?

I was thinking something about checking for presence in a directory, but that doesn't seem right. hasattr is implemented by calling getattr and checking if it rises, which I don't want.

+96
python
Mar 11 2018-11-11T00:
source share
8 answers

Yes, use getattr() to get the attribute, and callable() to make sure this is a method:

 invert_op = getattr(self, "invert_op", None) if callable(invert_op): invert_op(self.path.parent_op) 

Note that getattr() usually throws an exception if the attribute does not exist. However, if you specify a default value ( None , in this case), it will return it instead.

+156
Mar 11 2018-11-11T00:
source share

It works in both Python 2 and Python 3

 hasattr(connection, 'invert_opt') 

hasattr returns True if the connection object has a specific invert_opt function. Here is the documentation for you to graze

https://docs.python.org/2/library/functions.html#hasattr https://docs.python.org/3/library/functions.html#hasattr

+32
Apr 28 '15 at 7:57
source share

Is there a faster way to check if a function is defined, moreover, how to catch an exception?

Why are you against it? In most cases, Pythonic is better to ask forgiveness than permission .; -)

hasattr is implemented by calling getattr and checking if it rises, which I don't want.

Again, why? The following is pretty pythonic:

  try: invert_op = self.invert_op except AttributeError: pass else: parent_inverse = invert_op(self.path.parent_op) ops.remove(parent_inverse) 

Or

  # if you supply the optional `default` parameter, no exception is thrown invert_op = getattr(self, 'invert_op', None) if invert_op is not None: parent_inverse = invert_op(self.path.parent_op) ops.remove(parent_inverse) 

Note, however, that getattr(obj, attr, default) is mainly implemented by getattr(obj, attr, default) exception. There is nothing wrong with that on the land of Python!

+18
Mar 11 2018-11-11T00:
source share

I like Nathan Ostgard and I voted for it. But another way that you could solve your problem would be to use memoizing decorator, in which the cache would be the result of a function call. That way, you can go ahead and have an expensive function that is different, but when you call it again and again, subsequent calls are quick; The memoized version of the function looks for arguments in the dict, finds the result in the dict, when the actual function evaluates the result and immediately returns the result.

Here's a recipe for a memorable decorator named Raymond Hettinger's "lru_cache". The version of this standard is now standard in the functools module in Python 3.2.

http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/

http://docs.python.org/release/3.2/library/functools.html

+3
Mar 11 2018-11-11T00:
source share

The answers here check to see if the string is an attribute name of an object. An additional step (using the called) is needed to check if the attribute is a method.

So it comes down to the following: what is the fastest way to check if an obj object is associated with an attribute. Answer

 'attrib' in obj.__dict__ 

This is because dict hashes its keys, so checking for a key is quick.

See comparative comparisons below.

 >>> class SomeClass(): ... pass ... >>> obj = SomeClass() >>> >>> getattr(obj, "invert_op", None) >>> >>> %timeit getattr(obj, "invert_op", None) 1000000 loops, best of 3: 723 ns per loop >>> %timeit hasattr(obj, "invert_op") The slowest run took 4.60 times longer than the fastest. This could mean that an intermediate result is being cached. 1000000 loops, best of 3: 674 ns per loop >>> %timeit "invert_op" in obj.__dict__ The slowest run took 12.19 times longer than the fastest. This could mean that an intermediate result is being cached. 10000000 loops, best of 3: 176 ns per loop 
+3
Oct. 06 '16 at 22:03
source share

As in Python, if you try hard enough, you can figure out the guts and do something really nasty. Now, here is the nasty part:

 def invert_op(self, op): raise NotImplementedError def is_invert_op_implemented(self): # Only works in CPython 2.x of course return self.invert_op.__code__.co_code == 't\x00\x00\x82\x01\x00d\x00\x00S' 

Please do us a favor, just keep doing what you have in your question, and DO NOT use if you are not using the PyPy command hacking the Python interpreter. What you have there is Pythonic, what I have here is pure EVIL .

+2
Mar 11 2018-11-11T00:
source share

Although checking attributes in the __dict__ property is very quick, you cannot use this for methods since they do not appear in the __dict__ hash. However, you can resort to a hacker workaround in your class if the performance is so critical:

 class Test(): def __init__(): # redefine your method as attribute self.custom_method = self.custom_method def custom_method(self): pass 

Then check the method as:

 t = Test() 'custom_method' in t.__dict__ 

Time comparison with getattr :

 >>%timeit 'custom_method' in t.__dict__ 55.9 ns ± 0.626 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) >>%timeit getattr(t, 'custom_method', None) 116 ns ± 0.765 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) 

Not that I encouraged this approach, but it seems to work.

[EDIT] The performance improvement is even higher if the method name is not in this class:

 >>%timeit 'rubbish' in t.__dict__ 65.5 ns ± 11 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) >>%timeit getattr(t, 'rubbish', None) 385 ns ± 12.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
0
Mar 06
source share

You can also go through the class:

 import inspect def get_methods(cls_): members = inspect.getmembers(cls_) return dict([member for member in members if inspect.isfunction(member[1])]) # Example class A(object): pass class B(object): def foo(): print('B') # If you only have an object, you can use 'cls_ = obj.__class__' if 'foo' in get_methods(A): print('A has foo') if 'foo' in get_methods(B): print('B has foo') 
0
May 08 '19 at 6:16
source share



All Articles