2013-08-08 26 views
5

Tôi có một bộ mô tả về một lớp và phương thức __set__ của nó không được gọi. Tôi đã tìm kiếm lâu dài và khó khăn về điều này trong một vài giờ và không có câu trả lời cho điều này. Nhưng những gì tôi nhận thấy dưới đây là khi tôi gán 12 cho MyTest.X, nó sẽ xóa bộ mô tả thuộc tính cho X và thay thế nó bằng giá trị 12. Vì vậy, lệnh in cho hàm Get được gọi. Tốt lắm.Tại sao trình mô tả Python __set__ không được gọi là

Nhưng bản in cho chức năng __set__ KHÔNG được gọi. Tui bỏ lỡ điều gì vậy?

class _static_property(object): 
    ''' Descriptor class used for declaring computed properties that don't require a class instance. ''' 
    def __init__(self, getter, setter): 
     self.getter = getter 
     self.setter = setter 

    def __get__(self, instance, owner): 
     print "In the Get function" 
     return self.getter.__get__(owner)() 

    def __set__(self, instance, value): 
     print "In setter function" 
     self.setter.__get__()(value) 

class MyTest(object): 
    _x = 42 

    @staticmethod 
    def getX(): 
     return MyTest._x 

    @staticmethod 
    def setX(v): 
     MyTest._x = v 

    X = _static_property(getX, setX) 


print MyTest.__dict__ 
print MyTest.X 
MyTest.X = 12 
print MyTest.X 
print MyTest.__dict__ 
+0

Bạn có chắc chắn muốn sử dụng các thuộc tính lớp thay vì khởi tạo một cá thể không? – user2357112

+0

Trong trường hợp của tôi mà là rất phức tạp, đây là gói phương pháp tĩnh, mà cuối cùng được chuyển xuống phương pháp tĩnh C + +. –

+0

Ít nhất SWIG có một số vấn đề với các giao thức mô tả, vì vậy giải pháp có thể nằm trong lớp gói C++ của bạn, nếu bạn làm nhiều thứ phức tạp hơn được hiển thị ở đây. – schlenk

Trả lời

5

Hai câu trả lời khác ám chỉ đến việc sử dụng metaclasses để thực hiện những gì bạn muốn làm. Để giúp tìm hiểu về họ, đây là một ví dụ của việc áp dụng một mã trong câu hỏi của bạn mà làm cho nó làm những gì bạn muốn:

class _static_property(object): 
    """Descriptor class used for declaring computed properties that 
     don't require a class instance. 
    """ 
    def __init__(self, getter, setter): 
     self.getter = getter 
     self.setter = setter 

    def __get__(self, obj, objtype=None): 
     print("In the getter function") 
     return self.getter(obj) 

    def __set__(self, obj, value): 
     print("In setter function") 
     self.setter(obj, value) 

class _MyMetaClass(type): 
    def getX(self): 
     return self._x 

    def setX(self, v): 
     self._x = v 

    X = _static_property(getX, setX) 

class MyTest(object): 
    __metaclass__ = _MyMetaClass # Python 2 syntax 
    _x = 42 

#class MyTest(object, metaclass=_MyMetaClass): # Python 3 (only) syntax 
# _x = 42 

print(MyTest.__dict__) 
print(MyTest.X) 
MyTest.X = 12 
print(MyTest.X) 
print(MyTest.__dict__) 

Lớp học là trường hợp của metaclass của họ mà thường gõ type. Tuy nhiên, bạn có thể sử dụng nó như một lớp cơ sở và lấy ra siêu lớp con của riêng bạn - trong trường hợp này là một lớp có thuộc tính lớp là các bộ mô tả dữ liệu (còn gọi là các thuộc tính). Lưu ý rằng đối số self trong một phương thức meta hoặc meta-subclass là một cá thể metaclass, là một lớp. Trong mã ở trên, nó được đặt tên là MyTest.

+0

Cảm ơn bạn rất nhiều vì đã cho thấy một ví dụ về cách hoạt động. –

3

Các __set__ chỉ được gọi khi bạn gán cho X của một thể hiện

Nếu bạn muốn điều này để làm việc cho một attibute lớp, bạn sẽ phải thiết lập các mô tả trên metaclass của MyTest

+0

Có cách nào để làm cho nó làm những gì tôi muốn? –

+0

@CJohnson, chắc chắn, chỉ cần thực hiện một metaclass mà làm điều đó. –

+0

metaclass? Xin lỗi, tôi mới làm quen với python. –

4

Trình mô tả hoạt động trên các phiên bản của các lớp, không phải bản thân các lớp. Nếu bạn có một thể hiện của MyTest, X sẽ hoạt động như bạn mong đợi, nhưng truy cập nó như một thuộc tính lớp thực sự đặt thuộc tính của đối tượng lớp đó. Bạn có thể thử xác định một metaclass tùy chỉnh để thêm bộ mô tả, sau đó tạo MyTest với metaclass đó.

+0

Ok, đang tìm kiếm một lớp học meta bây giờ –

Các vấn đề liên quan