gpt4 book ai didi

python - 检查函数是否使用@classmethod

转载 作者:太空狗 更新时间:2023-10-29 17:39:23 25 4
gpt4 key购买 nike

TL;DR 如何确定一个函数是使用 @classmethod 还是具有相同效果的东西定义的?


我的问题

为了实现一个类装饰器,我想检查一个方法是否将类作为它的第一个参数,例如通过

@classmethod
def function(cls, ...):

我找到了通过 types 模块检查 @staticmethod 的解决方案(isinstance(foo, types.UnboundMethodType) False 如果 foo 是静态的,请参阅 here ),但没有找到关于如何为 @classmethod

执行此操作的任何内容

上下文

我想做的是一些类似的事情

def class_decorator(cls):
for member in cls.__dict__:
if (isclassmethod(getattr(cls, member))):
# do something with the method
setattr(cls, member, modified_method)
return cls

而且我不知道如何实现我在这个例子中称为isclassmethod的东西

最佳答案

如果对象是一个方法对象,那么有一个method.__self__ attribute ,并且该属性是您从中获取属性的类,那么它将把该类作为第一个参数。它已绑定(bind)到类。

请注意,此时您已经有了一个绑定(bind)对象,因此您不需要再次传入类,除非您首先从method.__func__< 中提取原始函数.

这里有一个例子,类Foo有一个类方法bar和一个常规方法baz,访问时没有绑定(bind)它直接上课:

>>> 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)),并在 method resolution order 中的类层次结构中的每个类中执行此操作:

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

并使用基类和派生类对上述两种方法进行全面测试,使用自定义描述符绑定(bind)函数,方式与 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() 函数正确区分了 classmethodnotclassmethod 描述符。


历史记录:此答案包括对 Python 2 的引用,但由于 Python 2 已达到 EOL,因此已被删除,因为不再相关。

关于python - 检查函数是否使用@classmethod,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19227724/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com