2009-02-28 38 views
135

Vì vậy, tôi đang chơi với trang trí trong Python 2.6, và tôi đang gặp một số vấn đề khiến chúng hoạt động. Dưới đây là tập tin lớp học của tôi:Tại sao @ foo.setter trong Python không hoạt động đối với tôi?

class testDec: 

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

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

Những gì tôi nghĩ điều này có nghĩa là để điều trị x như một tài sản, nhưng gọi các chức năng trên get và thiết lập. Vì vậy, tôi đã kích hoạt IDLE và đã kiểm tra IDLE:

>>> 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 

Rõ ràng cuộc gọi đầu tiên hoạt động như mong đợi, vì tôi gọi là getter, không có giá trị mặc định và không thành công. OK, tốt, tôi hiểu. Tuy nhiên, các cuộc gọi để gán t.x = 5 dường như tạo ra một tài sản mới x, và bây giờ getter không hoạt động!

Tôi đang thiếu gì?

+6

Hãy Đặt tên cho lớp học với một chữ in hoa văn. bạn có thể sử dụng chữ thường cho các biến và các tệp mô-đun. –

Trả lời

258

Bạn có vẻ đang sử dụng classic old-style classes. Để properties hoạt động chính xác, bạn cần sử dụng new-style classes thay vì (inherit from object). Chỉ cần khai báo lớp học của bạn như 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 

Nó hoạt động:

>>> 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 
>>> 
+2

Trong Python3 nó không cần thiết nữa - các lớp "cổ điển" chỉ là ok với setters :-) – Eenoku

+14

Nó hoạt động trong python 3 vì mỗi lớp là một lớp kiểu mới, không có lớp 'cổ điển' nữa. – craigds

22

Bạn cần phải sử dụng các lớp học kiểu mới mà bạn làm bằng cách bắt nguồn từ lớp học của bạn đối tượng:

class testDec(object): 
    .... 

Sau đó, nó sẽ làm việc.

61

Chỉ cần một lưu ý cho những người khác, những người vấp ngã ở đây tìm kiếm ngoại lệ này: cả hai chức năng cần phải có cùng tên. Đặt tên các phương pháp như sau sẽ cho kết quả trong một ngoại lệ:

@property 
def x(self): pass 

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

Thay vì cung cấp cho cả hai phương pháp cùng tên

@property 
def x(self): pass 

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

Nó cũng quan trọng cần lưu ý rằng thứ tự của các vấn đề khai. Bộ khởi động phải được xác định trước bộ đặt trong tệp hoặc nếu không bạn sẽ nhận được NameError: name 'x' is not defined

+0

Điều này có lẽ sẽ trở thành câu trả lời hay nhất "mới", với ngày càng nhiều người trên Python 3 ... – trpt4him

+3

Câu trả lời này rất tuyệt. Tôi nghĩ rằng để được hoàn thành, nó sẽ là tuyệt vời nếu bạn có thể nhận xét rằng thứ tự là quan trọng, đó là, getter phải được trước khi setter trong mã. Nếu không, bạn sẽ nhận được một 'NameError: name 'x' không được định nghĩa ngoại lệ. – eguaio

+0

Cảm ơn vì điều này. Tôi chỉ lãng phí phần tốt nhất của một ngày về điều này. Nó không bao giờ xảy ra với tôi rằng các phương pháp đã được gọi là cùng một điều. Thành ngữ thực sự bực bội! – ajkavanagh

8

Trong trường hợp bất kỳ ai đến đây từ google, ngoài các câu trả lời ở trên, tôi muốn thêm rằng điều này cần chú ý cẩn thận khi gọi setter từ phương pháp __init__ của lớp học của bạn dựa trên this answer Cụ thể:

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 
Các vấn đề liên quan