2010-01-23 43 views
13

Hãy xem xét các định nghĩa lớp sauPython: nhiều thuộc tính, một setter/getter

class of2010(object): 
    def __init__(self): 
     self._a = 1 
     self._b = 2 
     self._c = 3 

    def set_a(self,value): 
     print('setting a...') 
     self._a = value 
    def set_b(self,value): 
     print('setting b...') 
     self._b = value 
    def set_c(self,value): 
     print('setting c...') 
     self._c = value 
    a = property(fset=self.set_a) 
    b = property(fset=self.set_b) 
    c = property(fset=self.set_c) 

lưu ý rằng set_[a|b|c]() làm điều tương tự. là có một cách làm xác định:

def set_magic(self,value): 
    print('setting <???>...') 
    self._??? = value 

một lần và sử dụng nó cho a, b, c như sau

a = property(fset=self.set_magic) 
b = property(fset=self.set_magic) 
c = property(fset=self.set_magic) 

Trả lời

20
def attrsetter(attr): 
    def set_any(self, value): 
    setattr(self, attr, value) 
    return set_any 

a = property(fset=attrsetter('_a')) 
b = property(fset=attrsetter('_b')) 
c = property(fset=attrsetter('_c')) 
+0

Thuộc tính của nó (fset = ...), nhưng nếu không tôi sẽ sử dụng một cái gì đó như thế. – olt

+0

@olt: Cảm ơn, đã sửa. –

1

Có thể bạn đang tìm kiếm __setattr__(self, name, value)

Hãy xem here

2
class... 
def __setattr__(self, name, value): 
    print 'setting', name 
    self.__dict__[name] = value 

Vậy đó.

+1

Lời khuyên này đã lỗi thời. Theo https://docs.python.org/2/reference/datamodel.html#customizing-attribute-access, "Đối với các lớp kiểu mới, thay vì truy cập từ điển thể hiện,' __setattr__' nên gọi phương thức lớp cơ sở với cùng một tên, ví dụ, 'đối tượng .__ setattr __ (tự, tên, giá trị)'. " Lưu ý rằng OP đang sử dụng một lớp kiểu mới. –

5

Tôi thấy rằng người định cư của bạn chỉ cần đăng nhập một tin nhắn và sau đó chỉ cần gán giá trị - trên thực tế, câu trả lời được chấp nhận của bạn chỉ cần gán giá trị. Bạn đang sử dụng mô hình này bởi vì nó là Thực hành được chấp nhận/Trí tuệ thông thường trong một số ngôn ngữ khác, có lẽ một người có tên bắt đầu bằng chữ "J"? Nếu vậy, thì hãy biết rằng cách tiếp cận Pythonic để thiết kế này cùng là nhiều đơn giản hơn:

class Of2010(object): 
    def __init__(self): 
     self.a = 1 
     self.b = 2 
     self.c = 3 

Không làm-gì setters, không có chức năng trung gian gọi chỉ để gán một giá trị. "Cái gì ?!", bạn nói? "Tiếp xúc công khai với biến thành viên? !!" Vâng, thực sự.

Xem các lớp này từ quan điểm của mã khách hàng. Để sử dụng lớp học của bạn, khách hàng tạo ra một đối tượng, và sau đó gán thuộc tính "a" sử dụng:

obj = Of2010() 
obj.a = 42 

Đáng chú ý, đây là mã chính xác tương tự cho các lớp 5-liner tôi đã đăng ở trên.

Tại sao ngôn ngữ J khuyến khích phong cách thuộc tính tiết tú hơn? Để bảo vệ giao diện lớp trong trường hợp thay đổi trong tương lai trong các yêu cầu. Nếu tại một thời điểm nào đó, một số giá trị khác của đối tượng phải thay đổi trong buổi hòa nhạc với bất kỳ thay đổi nào đối với a, thì bạn phải thực hiện cơ chế đặc tính. Đáng buồn thay, ngôn ngữ J cho thấy bản chất của cơ chế truy cập thuộc tính đối với mã máy khách, để giới thiệu một thuộc tính tại một số điểm trong tương lai là một nhiệm vụ tái cấu trúc xâm nhập sẽ yêu cầu xây dựng lại tất cả các máy khách sử dụng lớp đó và thuộc tính "a" của nó.

Trong Python, không phải như vậy. Truy cập vào thuộc tính "a" của đối tượng được xác định trong thời gian chạy trong trình gọi. Vì truy cập trực tiếp và truy cập thuộc tính cả "nhìn" giống nhau, lớp Python của bạn bảo toàn giao diện này mặc dù cơ chế thực tế là khác nhau. Điều quan trọng là nó giống hệt như mã khách hàng có liên quan. Vì vậy, trong Java, người ta giới thiệu tính phức tạp của thuộc tính này ngay từ khi bắt đầu lớp này (và trên thực tế, bằng Thực hành được chấp nhận, của tất cả các lớp), trên cơ hội nó có thể trở nên cần thiết một số ngày trong Tương lai. Với Python, người ta có thể bắt đầu bằng cách thực hiện điều đơn giản nhất có thể làm việc, đó là, truy cập trực tiếp vào các biến thành viên đơn giản, để lại phương pháp phức tạp cho thời gian trong tương lai. Kể từ ngày đó có thể không bao giờ thực sự đến, đây là một bước tiến lớn trong việc nhận được phiên bản làm việc đầu tiên của mã của bạn ra khỏi cửa.

+0

Tôi muốn một hành động xảy ra bất cứ khi nào một số thành viên của (một thể hiện) một lớp được thiết lập. tôi muốn cùng một hành động xảy ra cho những thành viên này (ví dụ của tôi: in tên của thành viên) mà không cần nhân đôi người định cư của họ. đây là lý do tôi cần người định cư. nếu không, như bạn đã nói một cách khôn ngoan. Tôi sẽ không sử dụng chúng, vì chúng không cần thiết trong python – bandana

+0

Nếu nó đơn giản như việc in một tên trên mỗi lời gọi, tại sao không chỉ mã hóa nó thành __init __(), mà luôn luôn được gọi bởi mỗi cá thể? –

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