왜 파이썬에서 @ foo.setter가 작동하지 않습니까?


155

그래서 파이썬 2.6에서 데코레이터를 가지고 놀고 있는데, 그것들을 작동시키는 데 어려움이 있습니다. 내 수업 파일은 다음과 같습니다.

class testDec:

    @property
    def x(self): 
        print 'called getter'
        return self._x

    @x.setter
    def x(self, value): 
        print 'called setter'
        self._x = value

내가 생각한 것은 x속성처럼 취급 하지만 get 및 set에서 이러한 함수를 호출하는 것입니다. 그래서 유휴 상태를 발생시키고 확인했습니다.

>>> from testDec import testDec
from testDec import testDec
>>> t = testDec()
t = testDec()
>>> t.x
t.x
called getter
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "testDec.py", line 18, in x
    return self._x
AttributeError: testDec instance has no attribute '_x'
>>> t.x = 5
t.x = 5
>>> t.x
t.x
5

getter를 호출하기 때문에 첫 번째 호출은 예상대로 작동하며 기본값이 없으며 실패합니다. 알았어요, 이해합니다 그러나 할당 호출 t.x = 5은 새로운 속성을 생성하는 것으로 보이며 x이제 getter가 작동하지 않습니다!

내가 무엇을 놓치고 있습니까?


6
대문자로 수업 이름을 지정하십시오. 변수 및 모듈 파일에 소문자를 사용할 수 있습니다.
S.Lott

답변:


306

파이썬 2에서 고전적인 구식 클래스 를 사용하고있는 것 같습니다. 속성 이 제대로 작동하려면 대신 새 스타일 클래스 를 사용해야합니다 (파이썬 2에서는을 상속object 해야합니다 ). 클래스를 MyClass(object)다음 과 같이 선언하십시오 .

class testDec(object):

    @property
    def x(self): 
        print 'called getter'
        return self._x

    @x.setter
    def x(self, value): 
        print 'called setter'
        self._x = value

효과가있다:

>>> k = testDec()
>>> k.x
called getter
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/devel/class_test.py", line 6, in x
    return self._x
AttributeError: 'testDec' object has no attribute '_x'
>>> k.x = 5
called setter
>>> k.x
called getter
5
>>> 

문제를 일으킬 수있는 또 다른 세부 사항은 두 메소드 모두 특성이 작동하려면 동일한 이름이 필요하다는 것입니다. 이와 같은 다른 이름으로 setter를 정의하면 작동하지 않습니다 .

@x.setter
def x_setter(self, value):
    ...

그리고 처음에는 완전히 발견하기 쉽지 않은 또 하나의 순서는 순서입니다. 게터를 먼저 정의해야합니다 . 세터를 먼저 정의하면 name 'x' is not defined오류가 발생합니다.


4
Python3에서는 더 이상 필요하지 않습니다. "클래식"클래스는 setter만으로도 괜찮습니다 :-)
Eenoku

20
모든 클래스는 새로운 스타일의 클래스이므로 더 이상 '클래식'클래스가 없기 때문에 파이썬 3에서 작동합니다.
craigds

이 경우 데코레이터가 올바르게 처리되지 않으면 경고 / 오류가 발생해야한다고 생각합니다.
stfn

82

이 예외를 찾고있는 다른 사람들을위한 참고 사항입니다. 두 기능의 이름이 같아야합니다. 다음과 같이 메소드 이름을 지정하면 예외가 발생합니다.

@property
def x(self): pass

@x.setter
def x_setter(self, value): pass

대신 두 방법 모두 같은 이름을 지정하십시오

@property
def x(self): pass

@x.setter
def x(self, value): pass

선언의 순서가 중요하다는 점도 주목해야합니다. 파일에서 setter보다 먼저 getter를 정의해야합니다. 그렇지 않으면NameError: name 'x' is not defined


이것은 아마도 파이썬 3에 점점 더 많은 사람들과 함께 "새로운"최고의 답변이 될 것입니다 ...
trpt4him

5
이 답변은 훌륭합니다. 순서가 중요하다는 말, 즉 getter가 코드의 setter보다 앞에 있어야한다는 것을 말할 수 있다면 완전하다고 생각합니다. 그렇지 않으면 NameError: name 'x' is not defined예외 가 발생합니다.
eguaio

고마워 나는 이것에 하루의 가장 좋은 부분을 낭비했다. 그 방법을 똑같은 것으로 불러야 한 적이 없었습니다. 정말 실망스러운 작은 관용구!
ajkavanagh

이 답변의 "이유"를 이해하려면 여기에서 최종 문서를 읽으십시오. docs.python.org/2/library/functions.html#property 특히 "정확히 동등한"부분에 유의하십시오.
Evgeni Sergeev

23

객체에서 클래스를 파생시켜 새로운 스타일의 클래스를 사용해야합니다.

class testDec(object):
   ....

그런 다음 작동합니다.


위의 모든 것이 제자리에있었습니다. 이것은 python 2.7.x에서 클래스의 속성이 제대로 작동하기 위해 필요했습니다.
드론 브레인

12

아무도 구글에서 여기에 오는 경우 위의 답변 외에도이 답변을__init__ 기반으로 클래스 의 메소드 에서 세터를 호출 할 때주의를 기울여야한다고 덧붙이고 싶습니다 .

class testDec(object):                                                                                                                                            

    def __init__(self, value):
        print 'We are in __init__'
        self.x = value # Will call the setter. Note just x here
        #self._x = value # Will not call the setter

    @property
    def x(self):
        print 'called getter'
        return self._x # Note the _x here

    @x.setter
    def x(self, value): 
        print 'called setter'
        self._x = value # Note the _x here

t = testDec(17)
print t.x 

Output:
We are in __init__
called setter
called getter
17

뿐만 아니라에서 __init__방법,하지만 클래스의 다른 방법 프론.
Mia
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.