2015-09-24 1 views
1

В Python 3, я обнаружил, что атрибут класса может быть использован в качестве аргумента в __init__() функции, как показано ниже:Атрибут класса python не может использоваться в качестве аргумента для конструктора?

файл test.py:

class Foo: 
    var1 = 23333 
    def __init__(self, var=var1): 
     self.var = var 

работать в ЦМД:

C:\Users\rikka\Desktop>py -3 -i test.py 
>>> f1=Foo() 
>>> f1.var 
23333 

но с использованием выражения dot.expression, когда init этого класса, интерпретатор сообщит об ошибке:

файл test2.py:

class Foo: 
    var1 = 23333 
    def __init__(self, var=Foo.var1): 
     self.var = var 

работать в ЦМД:

C:\Users\rikka\Desktop>py -3 -i test2.py 
Traceback (most recent call last): 
    File "test2.py", line 1, in <module> 
    class Foo: 
    File "test2.py", line 3, in Foo 
    def __init__(self, var=Foo.var1): 
NameError: name 'Foo' is not defined 

Я просто не знаю, почему переводчик не может найти имя «Foo», так как Foo это имя в глобальной системе координат в окружающей среде. есть ли что-то связанное с понятием понятие о классе python, которое я не совсем понимаю?

+1

Пожалуйста, напишите, что вы на самом деле получаете без редактирования вручную. Второй образец кода с приглашением '>>>' выглядит как часть интерактивного сеанса Python, но трассировка происходит от выполнения скрипта. Если бы вы пробовали этот код в интерактивном режиме, вы бы увидели, что это определение класса, которое генерирует исключение, а не вызов для создания объекта. – Duncan

+0

@ Duncan за советом! –

ответ

6

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

Используйте часовой вместо этого, и в теле функции затем определить текущее значение Foo.var1:

def __init__(self, var=None): 
    if var is None: 
     var = Foo.var1 
    self.var = var 

я использовал None как стражи здесь, потому что он легко доступен и не часто необходим как фактическое значение. Если вам не нужно, чтобы быть в состоянии установить var как отдельное значение (т.е. не по умолчанию), используйте другой одноплодный часовой:

_sentinel = object() 

class Foo: 
    var = 23333 

    def __init__(self, var=_sentinel): 
     if var is _sentinel: 
      var = Foo.var1 
     self.var = var 
+0

Я не спускал вниз, но до тех пор, пока 'var1' не является изменяемым значением, вы можете просто написать' def __init __ (self, var = var1) ', поскольку' Foo' еще не в области видимости, но 'var1 'сам есть. (Если не намерено использовать любое значение 'Foo.var1', когда функция вызывается, и в этом случае дозорный - единственный способ пойти.) – chepner

+0

@chepner: Я также получил нижний предел для моего другого недавнего ответа в пределах 5 секунд, так что, возможно, я пометил кого-то по какой-то неопределенной причине. –

1

Проблемы заключается в том, что вы пытаетесь ссылаться на Foo во время самого строительства. В настоящий момент определено, что Foo.__init__ определено, когда Foo.var оценивается, Foo еще не существует (так как его методы, то есть Foo.__init__, еще не были полностью построены).

Параметры функции/метода по умолчанию разрешаются во время определения функции/метода. Классы доступны только после определения. Если определение метода класса (т. Е. Параметры) ссылается на сам класс, вы получаете круговую зависимость. Метод не может быть определен без класса, и класс не может быть определен без его метода.

См. Martijn Pieters, ответьте на вопрос о том, как реально подойти к таким зависимостям.

+1

Это Python 3; * все * классы автоматически наследуются от 'object'. –

+0

Пропустил это в открывшемся столбце, спасибо, что указал на него. Я удалил бит, чтобы избежать путаницы. – MisterMiyagi