Python 显式类对象需要作为自实现类方法装饰器中的第一个参数

Python 显式类对象需要作为自实现类方法装饰器中的第一个参数,python,python-decorators,class-method,Python,Python Decorators,Class Method,为了更好地理解decorator和classmethod,我正在编写classmethoddecorator的一个简单实现。这就是我面临的问题。当我用类的实例调用class方法时,一切正常,但用class对象调用方法失败,出现错误: >>**TypeError: wrapper() missing 1 required positional argument: 'cls'** 当我以显式类对象作为参数调用该方法时,它成功了,但是从类对象调用classmethod应该将类对象本身作为

为了更好地理解decorator和classmethod,我正在编写classmethoddecorator的一个简单实现。这就是我面临的问题。当我用类的实例调用class方法时,一切正常,但用class对象调用方法失败,出现错误:

>>**TypeError: wrapper() missing 1 required positional argument: 'cls'**

当我以显式类对象作为参数调用该方法时,它成功了,但是从类对象调用classmethod应该将类对象本身作为第一个参数传递,对吗

import functools
import inspect

def myclassmethod(meth):
    @functools.wraps(meth)
    def wrapper(cls, *args, **kwargs):
        #print(f'obj:{cls}, cls:{cls.__class__}, isclass:{inspect.isclass(cls)}')
        return meth(cls if inspect.isclass(cls) else cls.__class__, *args, **kwargs)
    return wrapper

class MyDecoratedMethods(object):
    _name = 'ClassName'

    def __init__(self):
        self._name = 'InstanceName'

    def __repr__(self):
        return f'{self.__class__.__name__}({self._name!r})'

    @myclassmethod
    def classname(cls):
        return cls._name

MyDecoratedMethods().classname()
#MyDecoratedMethods.classname()
MyDecoratedMethods.classname(MyDecoratedMethods) # This works

为了查看发生了什么,我删除了
@functools.wrapps(meth)
行,然后运行:

print(MyDecoratedMethods.classname)
# <function __main__.myclassmethod.<locals>.wrapper(cls, *args, **kwargs)>
因此,我们看到从类访问class方法将
实例
设置为
,从实例访问它将
实例
设置为该对象

但实际上我们根本不需要这个实例。我们可以在没有它的情况下实现逻辑

from functools import partial

class ClassMethod:
    def __init__(self, function):
        self.function = function

    def __get__(self, instance, cls):
        # create a new function and set cls to the first argument
        return partial(self.function, cls)

...

MyDecoratedMethods().classname()
# "ClassName"
MyDecoratedMethods.classname()
# "ClassName"
我们完成了。我们的自定义描述符完成了两件事:

  • 当从类的实例调用实例时,它阻止函数将实例绑定到第一个参数(就像函数通常成为方法一样)
  • 当从类或实例访问该类时,它总是将该类绑定到第一个参数

旁注:检查调用函数的实例或类是否也有缺陷的方法(
inspect.isclass(cls)
)。它适用于“普通”类,但不适用于元类,因为这样,
inspect.isclass
将为类及其实例返回
True

当我以显式类对象作为参数调用该方法时,它成功了,但是从类对象调用classmethod应该将类对象本身作为第一个参数传递,对吗?“-应该是这样的,但是classmethod实现负责通过,而您的实现没有这样做。谢谢,现在学习描述符协议。谢谢,我明白了,新代码现在运行良好,我正在阅读更多关于“描述符”的内容。”。
from functools import partial

class ClassMethod:
    def __init__(self, function):
        self.function = function

    def __get__(self, instance, cls):
        # create a new function and set cls to the first argument
        return partial(self.function, cls)

...

MyDecoratedMethods().classname()
# "ClassName"
MyDecoratedMethods.classname()
# "ClassName"