继承的 class 装饰方法 class 中的 cls 行为
cls behaviour in inherited classmethod of a decorated class
我正在尝试使用调用它们时使用的参数之一对 class 的 class 方法进行一些验证。
为此,我正在为 class 使用装饰器,它将装饰器应用于所需的方法,这将使用函数中的参数之一执行验证功能。
这一切都适用于基础 class(对于此示例,我将其称为 Parent
)。
但是,如果我创建另一个继承Parent
的class(在这个例子中我将其称为Child
),继承的修饰class方法不再表现正常。
Child
class 的 class 方法中的 cls
参数不是预期的 Child
,而是 Parent
.
以下面的例子
import inspect
def is_number(word):
if word.isdigit():
print('Validation passed')
else:
raise Exception('Validation failed')
class ClassDecorator(object):
def __init__(self, *args):
self.validators = args
def __decorateMethod(self):
def wrapped(method):
def wrapper(cls, word, *args, **kwargs):
for validator in self.validators:
validator(word)
return method(word, *args, **kwargs)
return wrapper
return wrapped
def __call__(self, cls):
for name, method in inspect.getmembers(cls):
if name == 'shout':
decoratedMethod = self.__decorateMethod()(method)
setattr(cls, name, classmethod(decoratedMethod))
return cls
@ClassDecorator(is_number)
class Parent(object):
@classmethod
def shout(cls, word):
print('{} is shouting {}'.format(cls, word))
@classmethod
def say(cls):
print('{} is talking'.format(cls))
class Child(Parent):
pass
Parent.shout('123')
Child.shout('321')
将产生以下输出:
Validation passed
<class '__main__.Parent'> is shouting 123
Validation passed
<class '__main__.Parent'> is shouting 321
我的问题是:
- 为什么
Child
的 class 方法被调用 Parent
作为 cls
- 是否可以使用此设计来获得所需的行为?
P.S.:我在 Python 2.7.10 和 Python 3.5.2 上都试过了,并且得到了相同的行为
您正在装饰绑定class方法;正是这个对象保留了 Parent
并在调用时将其传递给原始 shout
函数; cls
在您的 wrapper()
方法中绑定的任何内容都不会传入并被忽略。
先解包class方法,可以得到带有__func__
属性的底层函数对象:
def __call__(self, cls):
for name, method in inspect.getmembers(cls):
if name == 'shout':
decoratedMethod = self.__decorateMethod()(method.__func__)
setattr(cls, name, classmethod(decoratedMethod))
return cls
你现在必须考虑到你的包装器也在处理一个 unbound 函数,所以传递 cls
参数或手动绑定:
# pass in cls explicitly:
return method(cls, word, *args, **kwargs)
# or bind the descriptor manually:
return method.__get__(cls)(word, *args, **kwargs)
我正在尝试使用调用它们时使用的参数之一对 class 的 class 方法进行一些验证。
为此,我正在为 class 使用装饰器,它将装饰器应用于所需的方法,这将使用函数中的参数之一执行验证功能。
这一切都适用于基础 class(对于此示例,我将其称为 Parent
)。
但是,如果我创建另一个继承Parent
的class(在这个例子中我将其称为Child
),继承的修饰class方法不再表现正常。
Child
class 的 class 方法中的 cls
参数不是预期的 Child
,而是 Parent
.
以下面的例子
import inspect
def is_number(word):
if word.isdigit():
print('Validation passed')
else:
raise Exception('Validation failed')
class ClassDecorator(object):
def __init__(self, *args):
self.validators = args
def __decorateMethod(self):
def wrapped(method):
def wrapper(cls, word, *args, **kwargs):
for validator in self.validators:
validator(word)
return method(word, *args, **kwargs)
return wrapper
return wrapped
def __call__(self, cls):
for name, method in inspect.getmembers(cls):
if name == 'shout':
decoratedMethod = self.__decorateMethod()(method)
setattr(cls, name, classmethod(decoratedMethod))
return cls
@ClassDecorator(is_number)
class Parent(object):
@classmethod
def shout(cls, word):
print('{} is shouting {}'.format(cls, word))
@classmethod
def say(cls):
print('{} is talking'.format(cls))
class Child(Parent):
pass
Parent.shout('123')
Child.shout('321')
将产生以下输出:
Validation passed
<class '__main__.Parent'> is shouting 123
Validation passed
<class '__main__.Parent'> is shouting 321
我的问题是:
- 为什么
Child
的 class 方法被调用Parent
作为 cls - 是否可以使用此设计来获得所需的行为?
P.S.:我在 Python 2.7.10 和 Python 3.5.2 上都试过了,并且得到了相同的行为
您正在装饰绑定class方法;正是这个对象保留了 Parent
并在调用时将其传递给原始 shout
函数; cls
在您的 wrapper()
方法中绑定的任何内容都不会传入并被忽略。
先解包class方法,可以得到带有__func__
属性的底层函数对象:
def __call__(self, cls):
for name, method in inspect.getmembers(cls):
if name == 'shout':
decoratedMethod = self.__decorateMethod()(method.__func__)
setattr(cls, name, classmethod(decoratedMethod))
return cls
你现在必须考虑到你的包装器也在处理一个 unbound 函数,所以传递 cls
参数或手动绑定:
# pass in cls explicitly:
return method(cls, word, *args, **kwargs)
# or bind the descriptor manually:
return method.__get__(cls)(word, *args, **kwargs)