类装饰器 - 类字段的修改也改变了基类中的值

时间:2016-06-27 14:22:03

标签: python python-decorators

我用参数写了一个类装饰器。此装饰器需要设置类字段ID的值。我是按照以下方式做的:

class Base:
    ID = "ID_Base"
    def __init__(self, n):
        self.n = n

    def func(self):
        pass

def Test(cnt):
    def createTest(className):
        class _Test(className):
            def __init__(self, n):
                className.__init__(self, n)

            def func(self):
                for n in range(cnt):
                    className.func(self)

        name = className.__name__ + "_Test"
        _Test.__name__ = name
        globals()[name] = _Test

        _Test.ID = className.ID + '_test'
        className.ID = ''
        return _Test

    return createTest

@Test(2)
class Derived(Base):
    pass

print(Base.ID)
print(Derived.ID)
print(Derived_Test.ID)

在函数createTest中,我首先定义了从给定类类型派生的类,然后修改新_Test类的类名,并在当前模块中将其注册为全局类,然后(在最后一个块中) )我在ID类中设置_Test属性,并在作为参数传递的类中清除ID,并返回新类型。我这样做是为了获得以下结果:

ID_Base

ID_Base_test

然而,在运行之后我看到了这个:

ID_Base
ID_Base_test
ID_Base_test

为什么它会修改Derived类的属性而不是修饰器中创建的_Test?以及如何解决它?

我使用Python 2.6.6(Linux)和Python 3.4.1(Windows上的ActivePython)进行了检查。

编辑:我也尝试在_Test类中设置ID,如下所示,但结果相同:

def Test(cnt):
    def createTest(className):
        class _Test(className):
            ID = className.ID + '_test'

1 个答案:

答案 0 :(得分:2)

您从ID_Base_test获得print(Derived.ID)的原因是在装饰结束时存在隐式分配,这使Derived引用class Derived_Test。代码

@Test(2)
class Derived(Base):
    pass

等于

class Derived(Base):
    pass
Derived = Test(2)(Derived)

装饰后尝试print(Derived),您将获得__main__.Derived_Test

更新:请参阅this wiki了解更多解释。

  

装饰器是任何可调用的Python对象,用于修改函数,方法或类定义。装饰器传递给定义的原始对象,并返回一个修改过的对象,然后绑定到定义中的名称