如果该对象是一个方法对象,因此具有一个method.__self__
属性,并且该属性是您从中获取该属性的类,那么它将将该类作为第一个参数。它已绑定到类。
请注意,此时您已经有一个绑定对象,因此您不需要再次传入该类,除非您首先从method.__func__
.
这里举例说明,类Foo
有类方法bar
和常规方法baz
,直接在类上访问时不绑定:
>>> class Foo:
... @classmethod
... def bar(cls):
... pass
... def baz(self):
... pass
...
>>> Foo.baz
<function Foo.baz at 0x1097d1e18>
>>> Foo.bar
<bound method Foo.bar of <class '__main__.Foo'>>
>>> Foo.bar.__self__
<class '__main__.Foo'>
>>> Foo.bar.__self__ is Foo
True
调用会自动作为第一个参数Foo.bar()
传入。Foo.bar.__self__
如果您需要测试此类方法,请使用inspect.ismethod()
,如果返回True
测试__self__
属性:
import inspect
if inspect.ismethod(cls.method) and cls.method.__self__ is cls:
# method bound to the class, e.g. a classmethod
这也适用于任何类似的自定义描述符classmethod
。
如果您需要确定该方法是由对象生成的,则需要直接在类命名空间(或)classmethod
中查找属性,并按照方法解析顺序在类层次结构中的每个类中执行此操作:cls.__dict__
vars(cls)
def isclassmethod(method):
bound_to = getattr(method, '__self__', None)
if not isinstance(bound_to, type):
# must be bound to a class
return False
name = method.__name__
for cls in bound_to.__mro__:
descriptor = vars(cls).get(name)
if descriptor is not None:
return isinstance(descriptor, classmethod)
return False
并使用基类和派生类对上述两种方法进行全面测试,并使用自定义描述符以与 a 相同的方式绑定函数classmethod
,但它本身不是 a classmethod
:
>>> class notclassmethod:
... def __init__(self, f):
... self.f = f
... def __get__(self, _, typ=None):
... return self.f.__get__(typ, typ)
...
>>> class Base:
... @classmethod
... def base_cm(cls): pass
... @notclassmethod
... def base_ncm(cls): pass
... def base_m(self): pass
...
>>> class Derived(Base):
... @classmethod
... def derived_cm(cls): pass
... @notclassmethod
... def derived_ncm(cls): pass
... def derived_m(self): pass
...
>>> inspect.ismethod(Derived.base_cm) and Derived.base_cm.__self__ is Derived
True
>>> inspect.ismethod(Derived.base_ncm) and Derived.base_ncm.__self__ is Derived
True
>>> inspect.ismethod(Derived.base_m) and Derived.base_m.__self__ is Derived
False
>>> inspect.ismethod(Derived.derived_cm) and Derived.derived_cm.__self__ is Derived
True
>>> inspect.ismethod(Derived.derived_ncm) and Derived.derived_ncm.__self__ is Derived
True
>>> inspect.ismethod(Derived.derived_m) and Derived.derived_m.__self__ is Derived
False
>>> isclassmethod(Derived.base_cm)
True
>>> isclassmethod(Derived.base_ncm)
False
>>> isclassmethod(Derived.base_m)
False
>>> isclassmethod(Derived.derived_cm)
True
>>> isclassmethod(Derived.derived_ncm)
False
>>> isclassmethod(Derived.derived_m)
False
该isclassmethod()
函数正确区分classmethod
和notclassmethod
描述符。
历史注释:此答案包括对 Python 2 的引用,但由于 Python 2 已达到 EOL,因此不再相关。