Инициализация переменных класса Python - PullRequest
5 голосов
/ 14 декабря 2011

Я хотел бы хранить некоторую информацию о классе в виде переменных класса (статических).Тем не менее, я не могу понять, как эти вещи инициализируются.Вот простой пример:

class A(object):
    clsVar = 'a'
    @classmethod
    def clsMeth(cls):
        print 'changing clsVar'
        cls.clsVar = 'b'
    A.clsMeth()
# prints 'changing clsVar'

print A.clsVar    # prints 'a'
A.clsVar = 'b'
print A.clsVar    # prints 'b'

Поскольку функция была вызвана (как работает оператор print), почему переменная класса не изменилась?Нужно ли использовать метакласс, если я не хочу делать это после завершения определения класса?

[В частности, я хочу, чтобы clsMeth был декоратором, а переменная класса была списком всехфункции, которые были так украшены.Я предполагаю, что это неправильный способ добиться этого, поэтому я пошел дальше, но мне все еще любопытно.]

РЕДАКТИРОВАТЬ: Как отмечали многочисленные люди, код вышене побежитЯ запускал его в сеансе IPython, где вызов A.clsMeth() ссылался на предыдущую версию A и выполнялся.Наверное, таковы риски использования интерпретированного языка.Я закончил тем, что пошел примерно так:

outsideDict = {}
def outsideDec(func):
    outsideDict[func.__name__] = func

class A(object):
    @outsideDec
    def someMethod(self):
        print 'ID %s' % id(self)

    def otherMethod(self):
        print 'other'

print outsideDict
one, two = A(), A()
outsideDict['someMethod'](one)
outsideDict['someMethod'](two)

Возможно, это должен быть другой вопрос, но когда запускается outsideDec, есть ли способ сказать, к какому классу относится аргумент?Или есть лучший способ сделать самоанализ в Python?Я понимаю, что отклоняюсь от курса, поэтому приму ответ ниже и проведу дополнительные исследования.Спасибо всем!

Ответы [ 2 ]

4 голосов
/ 14 декабря 2011

Вызов A.clsMeth() в определении A не будет выполнен, так как A в этот момент не существует:

>>> class A(object):
...     clsVar = 'a'
...     @classmethod
...     def clsMeth(cls):
...         print 'changing clsVar'
...         cls.clsVar = 'b'
...     A.clsMeth()
... 
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "<stdin>", line 7, in A
NameError: name 'A' is not defined

Возможно, код работает, если A был определен ранее (например, если вы тестировали его в REPL), но вызов A.clsMeth был бы вызван для старого класса, который будет затенен новым.

Тем не менее, мы можем определенно поместить этот вызов после определения и получить желаемый результат:

>>> class A(object):
...     clsVar = 'a'
...     @classmethod
...     def clsMeth(cls):
...         print 'changing clsVar'
...         cls.clsVar = 'b'
...
>>> A.clsMeth()
changing clsVar
>>> A.clsVar
'b'

Конечно, как отметил fabianhrj, вы можете поместить его и в конструктор, но это невызывается, пока вы не создадите экземпляр.

0 голосов
/ 14 декабря 2011

Вам нужно поместить все операторы в функцию, чтобы они работали.Я рекомендую, чтобы, если вы хотите что-то запустить при создании объекта, просто поместите его в конструктор.

class A:
    def clsMeth(self):
        print("Changing clsVar")
        self.clsVar = 'b'
    def __init__(self):
        self.clsMeth()
    clsVar = 'a'

Вот и мы.

...