2016-06-27 2 views
0

Я написал декоратор класса с аргументом. Этот декоратор должен установить значение поля класса ID. Я делаю это в следующим образом:Class decorator - модификация значения поля класса изменяет значение в базовом классе тоже

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 (ActivePython в Windows).

Edit: Я также попытался установить ID внутри _Test класса, как показано ниже, но получил тот же результат:

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

Где Derived_Test исходит? есть ли у него аннотация? –

+0

Derived_Test имени создаются в декораторе, в частности, в этих строках: 'имя = имя класс .__ name__ + "_test"' ' _test .__ name__ = name' ' Глобал() [имя] = _Test' –

ответ

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, который используется для изменения функции, метода или определения класса. Декоратору передается исходный объект, который определяется и возвращает измененный объект, , который затем привязан к имени в определении.

+0

Спасибо за объяснение, это имеет смысл. –