为了更好地理解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.wraps(meth)
行,然后运行:这向我们展示了
MyDecoratedMethods.classname
只是您在decorator中创建的函数。这个函数对调用它的类一无所知。你知道吗但是,我们可以用Descriptors覆盖这个行为。描述符“知道”何时从类或实例访问它,最重要的是,它可以区分这些情况(这就是创建常规方法的方式)。你知道吗
这里是第一次尝试:
所以我们看到从类访问class方法将
instance
设置为None
,从实例访问它将instance
设置为该对象。你知道吗但实际上我们根本不需要这个实例。我们可以在没有它的情况下实现逻辑。你知道吗
我们结束了。我们的自定义描述符完成了两件事:
旁注:检查调用函数的实例或类是否也有缺陷(
inspect.isclass(cls)
)。它适用于“普通”类,但不适用于元类,因为inspect.isclass
为类及其实例返回True
。你知道吗相关问题 更多 >
编程相关推荐