Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 修饰类方法时出错_Python - Fatal编程技术网

Python 修饰类方法时出错

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)

我在做一个装饰员来装饰教室。对于实例方法,它工作得很好,但对于类方法,它给出了一个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)
    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中使用。