[关闭]
@songying 2018-07-12T16:07:03.000000Z 字数 1789 阅读 1072

属性管理,访问控制 -- 特殊方法

python特殊方法


__getattr__

  1. __getattr__(self, name)

当用户试图访问一个根本不存在(或者暂时不存在)的属性时,你可以通过这个魔法方法来定义类的行为。

这个可以用于捕捉错误的拼写并且给出指引,使用废弃属性时给出警告(如果你愿意,仍然可以计算并且返回该属性),以及灵活地处理AttributeError。

只有当试图访问不存在的属性时它才会被调用,所以这不能算是一个真正的封装的办法。

__setattr__

__getattr__ 不同, __setattr__ 可以用于真正意义上的封装。它允许你自定义某个属性的赋值行为,不管这个属性存在与否,也就是说你可以对任意属性的任何变化都定义自己的规则。然后,一定要小心使用 __setattr__ ,这个列表最后的例子中会有所展示。

__delattr__

这个魔法方法和 __setattr__ 几乎相同,只不过它是用于处理删除属性时的行为。和 __setattr__ 一样,使用它时也需要多加小心,防止产生无限递归(在__delattr__的实现中调用 del self.name 会导致无限递归)。

__getattribute__

__getattribute__ 看起来和上面那些方法很合得来,但是最好不要使用它。 __getattribute__ 只能用于新式类。在最新版的Python中所有的类都是新式类,在老版Python中你可以通过继承 object 来创建新式类。 __getattribute__ 允许你自定义属性被访问时的行为,它也同样可能遇到无限递归问题(通过调用基类的 __getattribute__`` 来避免)。getattribute基本上可以替代getattr` 。只有当它被实现,并且显式地被调用,或者产生 AttributeError 时它才被使用。 这个魔法方法可以被使用(毕竟,选择权在你自己),我不推荐你使用它,因为它的使用范围相对有限(通常我们想要在赋值时进行特殊操作,而不是取值时),而且实现这个方法很容易出现Bug。

__dir__(self)

定义对类的实例调用 dir() 时的行为,这个方法应该向调用者返回一个属性列表。一般来说,没必要自己实现 __dir__。但是如果你重定义了 __getattr__ 或者 __getattribute__ ,乃至使用动态生成的属性,以实现类的交互式使用,那么这个魔法方法是必不可少的。

  1. def __setattr__(self, name. value):
  2. self.name = value
  3. # 因为每次属性幅值都要调用 __setattr__(),所以这里的实现会导致递归
  4. # 这里的调用实际上是 self.__setattr('name', value)。因为这个方法一直
  5. # 在调用自己,因此递归将持续进行,直到程序崩溃
  6. def __setattr__(self, name, value):
  7. self.__dict__[name] = value # 使用 __dict__ 进行赋值
  8. # 定义自定义行为
  1. class AccessCounter(object):
  2. ''' 一个包含了一个值并且实现了访问计数器的类
  3. 每次值的变化都会导致计数器自增'''
  4. def __init__(self, val):
  5. super(AccessCounter, self).__setattr__('counter', 0)
  6. super(AccessCounter, self).__setattr__('value', val)
  7. def __setattr__(self, name, value):
  8. if name == 'value':
  9. super(AccessCounter, self).__setattr_('counter', self.counter + 1)
  10. # 使计数器自增变成不可避免
  11. # 如果你想阻止其他属性的赋值行为
  12. # 产生 AttributeError(name) 就可以了
  13. super(AccessCounter, self).__setattr__(name, value)
  14. def __delattr__(self, name):
  15. if name == 'value':
  16. super(AccessCounter, self).__setattr('counter', self.counter + 1)
  17. super(AccessCounter, self).__delattr(name)
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注