2013-04-26 30 views
11

I yêu Hệ thống trang trí @property của Python. Tôi thích rằng bạn có thể chạy mã tùy chỉnh khi bạn gọi aClassObect.attribute. Đặc biệt là để xác thực dữ liệu khi bạn đang thiết lập một thuộc tính. Tuy nhiên, một điều mà tôi muốn, nhưng tôi không thể tìm thấy, là một cách để chạy mã tùy chỉnh khi cố gắng thiết lập một thuộc tính không tồn tại. Ví dụ, nói tôi đã có những lớp sau:Phương pháp "bắt tất cả" Python cho các thuộc tính không xác định/chưa được thực hiện trong các lớp

class C(object): 
    def __init__(self): 
     self._x = None 

    @property 
    def x(self): 
     """I'm the 'x' property.""" 
     return self._x 

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

    @x.deleter 
    def x(self): 
     del self._x 

Bây giờ, nếu tôi có myObj, đó là một thể hiện của lớp C, và tôi gọi myObject.x = 42, nó sẽ chạy setter thích hợp, đó là rất tốt cho xác thực dữ liệu. Nhưng điều này không ngăn ai đó gọi số myOjbect.b = 47 và nó sẽ vui vẻ tạo thuộc tính mới có tên là b. Có cách nào để chạy mã đặc biệt khi thiết lập thuộc tính mới không? Tôi có khả năng tăng lỗi để nói điều gì đó như "lỗi, thuộc tính này không tồn tại".

+2

Tôi có một lớp học làm API cho cơ sở dữ liệu. Mỗi cá thể đại diện cho một mục nhập. Sau khi sửa đổi các thuộc tính của đối tượng, đại diện cho các trường trong cơ sở dữ liệu, bạn gọi 'object.save()' để cập nhật DB. Tôi muốn một lỗi được nâng lên chứ không phải là các lĩnh vực được âm thầm giảm vì họ không thực sự tồn tại trong DB. –

Trả lời

9

Để xây dựng một chút về câu trả lời của Elazar, bạn sẽ muốn ghi đè phương thức ma thuật __setattr__ và thực hiện kiểm tra để xem thuộc tính đã tồn tại hay chưa. Nếu không, hãy nêu một ngoại lệ. Đây là những gì có thể trông giống cho lớp học của bạn:

def __setattr__(self, name, value): 
    if not hasattr(self, name): # would this create a new attribute? 
     raise AttributeError("Creating new attributes is not allowed!") 
    super(C, self).__setattr__(name, value) 

Nó cũng có thể ghi đè lên __getattr__ hoặc __getattribute__ nếu bạn muốn để đối phó với các yêu cầu cho các thuộc tính không tồn tại, nhưng đối với các vấn đề cụ thể mà bạn đã mô tả điều này có lẽ không cần thiết.

Lưu ý rằng phương pháp __setattr__ tôi hiển thị ở trên sẽ không hoàn toàn phát độc đáo với thuộc tính hiện tại của bạn, do có sự cố. Nếu bạn xóa myObj.x, sau đó getter sẽ tăng ngoại lệ nếu bạn cố truy cập x sau đó. Điều này có nghĩa là hasattr sẽ trả về False khi kiểm tra xem x là thuộc tính hiện tại hay không và vì vậy, __getattr__ của tôi sẽ không cho phép bạn tạo lại. Nếu bạn thực sự cần để có thể xóa (và tạo lại) các thuộc tính cụ thể, bạn sẽ cần thực hiện __setattr__ phức tạp hơn (nó có thể kiểm tra trong lớp cho thuộc tính có tên mong muốn, thay vì chỉ dựa vào hasattr).

+0

oh chờ đợi, tôi đã rất chắc chắn điều này sẽ làm việc, nhưng có một bắt: hạn chế này áp dụng ở khắp mọi nơi, bao gồm cả trong các nhà xây dựng khi tôi đang khởi tạo các giá trị. Tôi chỉ thử nó, và nó dừng tôi với 'AttributeError' trong constructor. Có cách nào để giái quyết vấn đề này không? –

+0

@ J-bob: À, vâng. Bạn phải gọi một cách rõ ràng cái gì đó như 'siêu (C, tự) .__ setattr __ (" _ x ", None)' ở bất cứ đâu bạn đặt thuộc tính nếu bạn muốn bỏ qua kiểm tra. – Blckknght

+0

Tôi tìm thấy một giải pháp tốt. Ở đầu tệp của tôi, tôi 'nhập kiểm tra'. Sau đó, tôi thay thế dòng của bạn, 'nếu không hasattr (tự, tên):' với 'nếu không hasattr (tự, tên) và inspect.stack() [1] [3]! = '__init __':'. 'inspect.stack' cho phép bạn kiểm tra ngăn xếp cuộc gọi, vì vậy mã này kiểm tra tên của phương thức gọi nó. Nếu phương thức gọi là '__init__', nó cho phép tạo thuộc tính. Nếu không, nó sẽ làm tăng lỗi. Tôi khuyên bạn nên sửa đổi câu trả lời của bạn để hiển thị điều này. –

9

ghi đè __getattr____setattr__.

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