2012-02-03 34 views
5

tôi muốn thêm nhiều hình nộm-tính đến một lớp học thông qua một trang trí, như thế này:Làm cách nào để thêm thuộc tính vào lớp bằng trình trang trí có danh sách tên làm đối số?

def addAttrs(attr_names): 
    def deco(cls): 
    for attr_name in attr_names: 
     def getAttr(self): 
     return getattr(self, "_" + attr_name) 
     def setAttr(self, value): 
     setattr(self, "_" + attr_name, value) 
     prop = property(getAttr, setAttr) 
     setattr(cls, attr_name, prop) 
     setattr(cls, "_" + attr_name, None) # Default value for that attribute 
    return cls 
    return deco 

@addAttrs(['x', 'y']) 
class MyClass(object): 
    pass 

Thật không may, decoarator dường như để giữ tham chiếu của attr_name thay vì nội dung của nó. Do đó, MyClass.xMyClass.y truy cập cả MyClass._y:

a = MyClass() 
a.x = 5 
print a._x, a._y 
>>> None, 5 
a.y = 8 
print a._x, a._y 
>>> None, 8 

gì làm tôi phải thay đổi để có được những hành vi mong đợi?

Trả lời

7

Bạn gần như đã làm việc. Chỉ có một nit. Khi tạo các chức năng bên trong, ràng buộc giá trị hiện tại của attr_name vào các chức năng getter và setter:

def addAttrs(attr_names): 
    def deco(cls): 
    for attr_name in attr_names: 
     def getAttr(self, attr_name=attr_name): 
     return getattr(self, "_" + attr_name) 
     def setAttr(self, value, attr_name=attr_name): 
     setattr(self, "_" + attr_name, value) 
     prop = property(getAttr, setAttr) 
     setattr(cls, attr_name, prop) 
     setattr(cls, "_" + attr_name, None) # Default value for that attribute 
    return cls 
    return deco 

@addAttrs(['x', 'y']) 
class MyClass(object): 
    pass 

này tạo ra kết quả dự kiến:

>>> a = MyClass() 
>>> a.x = 5 
>>> print a._x, a._y 
5 None 
>>> a.y = 8 
>>> print a._x, a._y 
5 8 

Hope this helps. Chúc mừng trang trí :-)

2

Python không hỗ trợ phạm vi cấp khối, chỉ cấp chức năng. Do đó, bất kỳ biến nào được gán trong vòng lặp sẽ có sẵn bên ngoài vòng lặp làm giá trị có sẵn cuối cùng. Để có được kết quả mà bạn đang tìm kiếm, bạn sẽ cần phải sử dụng một đóng cửa trong vòng lặp:

def addAttrs(attr_names): 
    def deco(cls): 
    for attr_name in attr_names: 
     def closure(attr): 
     def getAttr(self): 
      return getattr(self, "_" + attr) 
     def setAttr(self, value): 
      setattr(self, "_" + attr, value) 
     prop = property(getAttr, setAttr) 
     setattr(cls, attr, prop) 
     setattr(cls, "_" + attr, None) 
     closure(attr_name) 
    return cls 
    return deco 

Sử dụng việc đóng cửa closure, các thuộc tính được gán trong getAttrsetAttr sẽ được scoped một cách chính xác.

CHỈNH SỬA: chỉnh sửa thụt đầu dòng

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