Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/298.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.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_Decorator_Interpreter - Fatal编程技术网

Python 装饰一门课——装饰一次就忘了它?

Python 装饰一门课——装饰一次就忘了它?,python,decorator,interpreter,Python,Decorator,Interpreter,我成功地创建了一个装饰器来装饰任何类型的类,为它们添加了一个标准接口,以便于访问、集成等 我一直反对使用元类,因为这方面的文献说这是一种过度使用,大多数情况下可以用类装饰器来代替。困扰我的是: def Decorator(somearg): def wrapper(cls): clsinit = cls.__init__ cls.members = [] def __init__(self, *args, **kwargs):

我成功地创建了一个装饰器来装饰任何类型的类,为它们添加了一个标准接口,以便于访问、集成等

我一直反对使用元类,因为这方面的文献说这是一种过度使用,大多数情况下可以用类装饰器来代替。困扰我的是:

def Decorator(somearg):

    def wrapper(cls):
        clsinit = cls.__init__
        cls.members = []

        def __init__(self, *args, **kwargs):
            #do something with somearg...
            self.__class__.members.append(self)
            clsinit(self,*args,**kwargs)

        cls.__init__ = clsinit
        return cls

    return wrapper

@Decorator('thearg')
class A(object):
    pass

a = A()
b = A()
使用python调试器,在导入时,类A立即用参数“thearg”修饰。但是每次我实例化一个()时,实例都直接调用decorator中定义的init,而不经过前面的层。这很好,因为我希望我的类记录每个成员,而不是每次实例化新实例时都重置。但我不确定我是否理解原因


有人能解释一下python解释器在这种特定情况下的物理特性吗?

如果您只是更改类而不是创建新类,那么就不需要包装器函数(应该是包装器类):

顺便说一句,您应该创建一个基类并从中继承:

class Base(object):
    members = []
    def __init__(self):
        self.__class__.members.append(self)

class A(Base):
    pass

更干净

好的,参考更新问题中更正的代码,您会问:

但是每次我实例化一个()时,实例都直接调用 在decorator中定义的init,不经过上一个 分层。”


这是因为当
decorator()
函数创建的
wrapper()
类decorator函数应用于
类A
,它将
A
\uuu init\uuuuu()
替换为自己的动态定义的
包装器。当
A
s被实例化时,就会调用该函数。编写该函数时,首先要做一些事情,然后在最后调用原始的
A.\uuu init\uuu()

感谢@JBernardo和@martineau的回答。我编写这段代码的目的是实现类对象类似容器的行为,以便更容易地访问它们的实例。但我希望每次访问一个相对于每个类的实例,而不是访问同一继承类中的所有实例

实际上,再次编写代码帮助我理解了我的问题:

a) 使用其参数somearg调用Decorator

b) 下一行的内容(类A的定义)用作包装器函数的参数。在这一职能范围内: 1) 记住初始类init以避免无限递归 2) 定义新的init以在实例级别进行更改 3) 为类绑定一个新的init方法 4) 返回已转换的类对象


c) 因为返回值是一个类对象,所以每次实例化一个实例时,我都会直接转到init,因为这就是它在新类中的绑定方式。

您发布的代码有问题。它有一个语法错误,可能具有
somearg
cls
触发器的角色。它是您真实代码的简化版本吗?请测试并修复。这确实是元类应该用来做的事情。如果不显式地修饰每个子类,装饰程序就无法处理它。我确实在代码上犯了一个错误:我现在就编辑它。我创建包装器函数是因为我需要在装饰时使用一个参数以某种方式实现实例化。还有,我试过继承!但我的问题是,母类成为所有子类的容器,这是不需要的行为。如果我装饰,所有装饰过的类都会成为它们自己的容器。
class Base(object):
    members = []
    def __init__(self):
        self.__class__.members.append(self)

class A(Base):
    pass