Làm thế nào là __getattribute__
phương pháp được sử dụng?
Nó được gọi trước khi tra cứu dạng chấm thông thường. Nếu nó tăng lên AttributeError
, sau đó chúng tôi gọi __getattr__
.
Sử dụng phương pháp này là khá hiếm. Chỉ có hai định nghĩa trong thư viện chuẩn:
$ grep -Erl "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py
Thực hành tốt nhất
Cách thích hợp để kiểm soát lập trình quyền truy cập vào một thuộc tính duy nhất là với property
. Lớp D
phải được viết như sau (với bộ cài đặt và bộ xóa tùy chọn để sao chép hành vi dự kiến rõ ràng):
class D(object):
def __init__(self):
self.test2=21
@property
def test(self):
return 0.
@test.setter
def test(self, value):
'''dummy function to avoid AttributeError on setting property'''
@test.deleter
def test(self):
'''dummy function to avoid AttributeError on deleting property'''
Và cách sử dụng:
>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
Thuộc tính là một bộ mô tả dữ liệu, do đó nó là thứ đầu tiên được tìm kiếm trong thuật toán tra cứu dạng chấm thông thường.
Tùy chọn cho __getattribute__
Bạn có một số tùy chọn nếu bạn thực sự cần triển khai tra cứu cho mọi thuộc tính thông qua __getattribute__
.
- tăng
AttributeError
, gây ra __getattr__
được gọi (nếu được thực hiện)
- trả lại một cái gì đó từ nó bằng cách
- sử dụng
super
để gọi triển khai cha (có thể object
là)
- kêu gọi
__getattr__
- triển khai thuật toán tra cứu dạng chấm của riêng bạn bằng cách nào đó
Ví dụ:
class NoisyAttributes(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self, name):
print('getting: ' + name)
try:
return super(NoisyAttributes, self).__getattribute__(name)
except AttributeError:
print('oh no, AttributeError caught and reraising')
raise
def __getattr__(self, name):
"""Called if __getattribute__ raises AttributeError"""
return 'close but no ' + name
>>> n = NoisyAttributes()
>>> nfoo = n.foo
getting: foo
oh no, AttributeError caught and reraising
>>> nfoo
'close but no foo'
>>> n.test
getting: test
20
Những gì bạn muốn ban đầu.
Và ví dụ này cho thấy cách bạn có thể làm những gì bạn muốn ban đầu:
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else:
return super(D, self).__getattribute__(name)
Và sẽ hành xử như thế này:
>>> o = D()
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
>>> del o.test
Traceback (most recent call last):
File "<pyshell#216>", line 1, in <module>
del o.test
AttributeError: test
Đánh giá mã
Mã của bạn với nhận xét. Bạn có một chấm điểm tra cứu về bản thân __getattribute__
. Đây là lý do tại sao bạn gặp lỗi đệ quy. Bạn có thể kiểm tra xem tên có phải là "__dict__"
và sử dụng super
để giải quyết hay không, nhưng điều đó không bao gồm __slots__
. Tôi sẽ để nó như một bài tập cho người đọc.
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else: # v--- Dotted lookup on self in __getattribute__
return self.__dict__[name]
>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp