Python 修饰类方法时出错
我在做一个装饰员来装饰教室。对于实例方法,它工作得很好,但对于类方法,它给出了一个TypeError。代码如下:Python 修饰类方法时出错,python,Python,我在做一个装饰员来装饰教室。对于实例方法,它工作得很好,但对于类方法,它给出了一个TypeError。代码如下: def deco_method(fn): def wrapper(*arg, **kwarg): """ Function: Wrapper """ print "Calling function {}".format(fn.__name__) print arg, kwarg ret_val = fn(*arg, **kwarg)
def deco_method(fn):
def wrapper(*arg, **kwarg):
"""
Function: Wrapper
"""
print "Calling function {}".format(fn.__name__)
print arg, kwarg
ret_val = fn(*arg, **kwarg)
print "Executed function {}".format(fn.__name__)
return ret_val
return wrapper
def clsdeco(cls):
attributes = cls.__dict__.keys()
for attribute in attributes:
# Do not decorate private methods
if '__' in attribute:
continue
# Get the method
value = getattr(cls, attribute)
if not hasattr(value, '__call__'):
continue
# CHeck if method is a class method or normal method and decoate accordingly
if value.im_self is None:# non class method
setattr(cls, attribute, deco_method(value))
elif value.im_self is cls: # CHeck if the method is class method
setattr(cls, attribute, classmethod(deco_method(value)))
else:
assert False
return cls # return decorated class
@clsdeco
class Person:
message = "Hi Man"
def __init__(self, first_name, last_name):
self.fname = first_name
self.lname = last_name
self.age = None
def get_name(self):
print "Name is '{} {}'".format(self.fname, self.lname)
@classmethod
def greet_person(cls):
print cls.message
p = Person('John', 'snow')
p.greet_person()
它给出了一个错误:
TypeError:greet\u person()只接受1个参数(给定2个)
如果我删除@clsdeco,它会工作得非常好
你知道我在这里遗漏了什么吗?如果你添加显示的行,它会工作的。这是因为类定义中应用的@classmethod decorator更改了
getattr(cls,attribute)
返回的内容,它将是命名方法的描述符,该方法添加cls
参数,然后调用实方法
您需要做的是检索属性的“原始”值,它只是一个常规函数,然后通过显式调用classmethod
将其转换回类方法。此所需的“原始”值存储在与同一属性名称关联的类字典中,因此需要添加value=cls.\uuuuuuuu dict.\uuuu func.\uuuu
行
为了正确处理静态方法,还需要类似的东西。如何为所有不同类型的方法做到这一点在问题的部分中进行了描述。其他一些答案也比我这里描述的更详细
def clsdeco(cls):
attributes = cls.__dict__.keys()
for attribute in attributes:
# Do not decorate private methods
if '__' in attribute:
continue
# Get the method
value = getattr(cls, attribute)
if not hasattr(value, '__call__'):
continue
# Check if method is a class method or normal method and decoate accordingly
if value.im_self is None:# non class method
setattr(cls, attribute, deco_method(value))
elif value.im_self is cls: # Check if the method is class method
value = cls.__dict__[attribute].__func__ # ADDED
setattr(cls, attribute, classmethod(deco_method(value)))
else:
assert False
return cls # return decorated class
谢谢我没有注意到getattr返回描述符。“value=cls.\uuuuu dict\uuuuuuu[attribute]。\uuuuuu func\uuuuuuuuu”有效。或者我们也可以做“value=value.im_func”[Python2.7]和“value=value.im_func”[Python3]@Luminos:在Python2.6中,他们为
im_func
制作了一个alais,所以使用它会更方便,但我相信使用cls.\uu dict\uuuu[attribute]._func__
已经可以在Python2和Python3中使用。