检查函数是否使用@classmethod [英] Check if a function uses @classmethod

查看:84
本文介绍了检查函数是否使用@classmethod的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

TL;DR How do I find out whether a function was defined using @classmethod or something with the same effect?

我的问题

用于实施课程装饰器我想检查一个方法是否将类作为其第一个参数,例如通过

For implementing a class decorator I would like to check if a method takes the class as its first argument, for example as achieved via

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

我找到了一种检查<$的解决方案c $ c> @staticmethod 通过 types 模块( isinstance(foo,types.UnboundMethodType) foo 是静态的,则c>为 False ,请参见此处),但没有找到有关 @classmethod

I found a solution to check for @staticmethod via the types module (isinstance(foo, types.UnboundMethodType) is False if the foo is static, see here), but did not find anything on how to do so for @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 在此示例中

and I do not know how to implement what I called isclassmethod in this example

推荐答案

如果对象是方法对象,依此类推具有 方法。__self __ 属性,并且该属性是您从中获得该属性的类,那么它将把该类作为第一个参数。它已经绑定到该类。

If the object is a method object, and so has a method.__self__ attribute, and that attribute is the class you got the attribute from, then it'll take the class as the first argument. It has been bound to the class.

请注意,此时您已经具有一个绑定对象,因此您无需传递类< ,除非您首先从方法中提取原始函数。__func __

Note that you already have a bound object at this point, so you don't need to pass in the class again, unless you first extract the original function from method.__func__.

这里是一个说明, class Foo 有一个类方法 bar 和一个常规方法 baz ,当您直接在类上访问它时不受限制:

Here is an illustration, the class Foo has a class method bar and a regular method baz, which is not bound when you access it directly on the class:

>>> 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 __ 作为第一个参数。

Calling Foo.bar() automatically passes in Foo.bar.__self__ as the first argument.

如果需要测试这种方法,请使用 inspect.ismethod() ,如果返回 True ,请测试 __ self __ 属性:

If you need to test such methods, use inspect.ismethod(), and if that returns True test the __self__ attribute:

import inspect

if inspect.ismethod(cls.method) and cls.method.__self__ is cls:
    # method bound to the class, e.g. a classmethod

这应该适用于任何 custom 描述符,它们的作用类似于

This should work for any custom descriptors that work like classmethod does, as well.

如果您需要确定地知道该方法是由 classmethod 。 c>对象,则需要直接在类名称空间中查找属性( cls .__ dict __ vars(cls)),并在方法解析的类层次结构中的每个类中进行操作顺序

If you need to know with certainty that the method was produced by a classmethod object, you'll need to look up the attributes directly in the class namespace (cls.__dict__ or vars(cls)), and do so in each class in the class hierarchy in 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

,并使用基类和派生类对上述两种方法进行全面测试,并使用自定义描述符绑定函数的方式与 classmethod 相同,但本身不是 classmethod

and a full test of the above two approaches using a base class and a derived class, with a custom descriptor that binds a function the same way a classmethod would, but is not, itself, 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 描述符。

The isclassmethod() function correctly distinguishes between the classmethod and notclassmethod descriptors.

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

Historical note: this answer included references to Python 2, but with Python 2 having reached EOL were removed as no longer relevant.

这篇关于检查函数是否使用@classmethod的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆