I want to know if a function is defined for an instance of a class
class c(object):
def func(self): pass
cc = c()
>>> is_function_defined_for_instance(cc,'func')
True
>>> is_function_defined_for_instance(cc,'cnuf')
False
my cleanest attempts at the function is:
def is_function_defined_for_instance(instance,function):
return callable(getattr(instance,function,None))
# returns True iff function is defined for class of i开发者_如何学JAVAnstance (not super classes)
def is_function_defined_for_instance(instance,function):
return bool(instance.__class__.__dict__.get(function))
is there a built-in or a nicer way to accomplish what I'm looking for?
In Python 2.6 or better, the recommended approach is:
import collections
def is_func(instance, func):
return isinstance(getattr(instance, func, None), collections.Callable)
The new ABCs (Abstract Base Classes) in the collections
module are the correct way, in Python 2.6+ and 3.any, to perform this kind of "duck-typing-like type checks" -- much more elegant, unform, and future-proof than older approaches such as the callable
built-in, operator.isCallable
, or checking for the presence of specific special methods such as __call__
. Since isinstance
can now be overloaded, leave it up to the ABCs to overload it and perform the checks by encapsulating whatever lower-level approaches work best!
The elegance and advantages of the new approach are such that, if you need to make your code portable between older and newer versions of Python, I recommend encapsulating the "duck-typing tests" that you require in a module that can define its function depending on the sys.version
-- using isinstance(x, collections.Y)
in 2.6 or better, and older approaches such as hasattr(x, '__somespecialmethod__')
or callable(x)
in 2.5 or worse.
Most importantly, and more generally, don't pollute your new, mainline application code with the old, inferior ways -- if backwards-portability requirements force your overall system to have some "garbage" (in order to keep running on old Python versions), at least hide that garbage decently in its own "compartment" (where one day you may be able to easily sweep it away if your app's deployment constraints permit!-).
>>> def is_func(instance, func):
test = getattr(instance, func, None)
if test and hasattr(test, '__call__'):
return True
>>> is_func('', 'len')
>>> is_func({}, 'fromkeys')
True
or you could use inspect
module:
>>> import inspect
>>> test = getattr(cc, 'func', None)
>>> inspect.ismethod(test)
True
Can you throw some sort of custom exception if the method is missing? (I'm coming from Ruby land here :) )
精彩评论