75 lines
3.1 KiB
Markdown
75 lines
3.1 KiB
Markdown
|
|
# 三、属性的访问控制 #
|
|||
|
|
|
|||
|
|
之前也有讲到过,Python 没有真正意义上的私有属性。然后这就导致了对 Python 类的封装性比较差。我们有时候会希望 Python 能够定义私有属性,然后提供公共可访问的 get 方法和 set 方法。Python 其实可以通过魔术方法来实现封装。
|
|||
|
|
|
|||
|
|
|方法|说明|
|
|||
|
|
| ---| --- |
|
|||
|
|
|`__getattr__(self, name)`|该方法定义了你试图访问一个不存在的属性时的行为。因此,重载该方法可以实现捕获错误拼写然后进行重定向, 或者对一些废弃的属性进行警告。|
|
|||
|
|
|`__setattr__(self, name, value)`|定义了对属性进行赋值和修改操作时的行为。不管对象的某个属性是否存在,都允许为该属性进行赋值.有一点需要注意,实现 `__setattr__` 时要避免"无限递归"的错误,|
|
|||
|
|
|`__delattr__(self, name)`|`__delattr__` 与 `__setattr__` 很像,只是它定义的是你删除属性时的行为。实现 `__delattr__` 是同时要避免"无限递归"的错误|
|
|||
|
|
|`__getattribute__(self, name)`|`__getattribute__` 定义了你的属性被访问时的行为,相比较,`__getattr__` 只有该属性不存在时才会起作用。因此,在支持 `__getattribute__ `的 Python 版本,调用`__getattr__` 前必定会调用 `__getattribute__``__getattribute__` 同样要避免"无限递归"的错误。|
|
|||
|
|
|
|||
|
|
通过上面的方法表可以知道,在进行属性访问控制定义的时候你可能会很容易的引起一个错误,可以看看下面的示例:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def __setattr__(self, name, value):
|
|||
|
|
self.name = value
|
|||
|
|
# 每当属性被赋值的时候, ``__setattr__()`` 会被调用,这样就造成了递归调用。
|
|||
|
|
# 这意味这会调用 ``self.__setattr__('name', value)`` ,每次方法会调用自己。这样会造成程序崩溃。
|
|||
|
|
|
|||
|
|
def __setattr__(self, name, value):
|
|||
|
|
# 给类中的属性名分配值
|
|||
|
|
self.__dict__[name] = value
|
|||
|
|
# 定制特有属性
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
上面方法的调用具体示例如下:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: UTF-8 -*-
|
|||
|
|
|
|||
|
|
class User(object):
|
|||
|
|
def __getattr__(self, name):
|
|||
|
|
print('调用了 __getattr__ 方法')
|
|||
|
|
return super(User, self).__getattr__(name)
|
|||
|
|
|
|||
|
|
def __setattr__(self, name, value):
|
|||
|
|
print('调用了 __setattr__ 方法')
|
|||
|
|
return super(User, self).__setattr__(name, value)
|
|||
|
|
|
|||
|
|
def __delattr__(self, name):
|
|||
|
|
print('调用了 __delattr__ 方法')
|
|||
|
|
return super(User, self).__delattr__(name)
|
|||
|
|
|
|||
|
|
def __getattribute__(self, name):
|
|||
|
|
print('调用了 __getattribute__ 方法')
|
|||
|
|
return super(User, self).__getattribute__(name)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
user = User()
|
|||
|
|
# 设置属性值,会调用 __setattr__
|
|||
|
|
user.attr1 = True
|
|||
|
|
# 属性存在,只有__getattribute__调用
|
|||
|
|
user.attr1
|
|||
|
|
try:
|
|||
|
|
# 属性不存在, 先调用__getattribute__, 后调用__getattr__
|
|||
|
|
user.attr2
|
|||
|
|
except AttributeError:
|
|||
|
|
pass
|
|||
|
|
# __delattr__调用
|
|||
|
|
del user.attr1
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
输出的结果:
|
|||
|
|
|
|||
|
|
```txt
|
|||
|
|
调用了 __setattr__ 方法
|
|||
|
|
调用了 __getattribute__ 方法
|
|||
|
|
调用了 __getattribute__ 方法
|
|||
|
|
调用了 __getattr__ 方法
|
|||
|
|
调用了 __delattr__ 方法
|
|||
|
|
```
|