内容简介:Python 中有三个看上去非常相似的魔法方法:首先来看看但是, 如果你在定义类的时候实现了
Python 中有三个看上去非常相似的魔法方法: __getattribute__
, __getattr__
, __getitem___
, 就是前面这仨哥们儿了.
不同之处
首先来看看 __ getattribute__
和 __getattr__
, 这俩在一定程度上有先后调用的关系. 简单来说, 在用 .
运算符获取某个实例的属性值的时候, Python 解释器会首先调用 __getattribute__
, 如果该实例中有需要获取的属性值, 就返回属性值, 如果没有, 则会抛出 AttributeError
.
class Foo: def __init__(self, a): self.a = a def __getattribute__(self, key): print('I\'m in __getattribute__ func') return super(Foo, self).__getattribute__(key) foo = Foo(3) print(foo.a) # 访问存在的属性 print(foo.b) # 访问不存在的属性 # 执行结果如下: I'm in __getattribute__ func 3 I'm in __getattribute__ func --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-29-1f8f708fdf11> in <module>() 16 foo = Foo(3) 17 print(foo.a) # 访问存在的属性 ---> 18 print(foo.b) # 访问不存在的属性 <ipython-input-29-1f8f708fdf11> in __getattribute__(self, key) 5 def __getattribute__(self, key): 6 print('I\'m in __getattribute__ func') ----> 7 return super(Foo, self).__getattribute__(key) 8 AttributeError: 'Foo' object has no attribute 'b' 复制代码
但是, 如果你在定义类的时候实现了 __getattr__
方法, 那么在 __getattribute__
抛出 AttributeError
后, 就会执行 __getattr__
. 当然, 如果 __getattribute__
获取到了属性值, __ getattr__
就不会被调用.
class Foo: def __init__(self, a): self.a = a def __getattribute__(self, key): print('I\'m in __getattribute__ func') return super(Foo, self).__getattribute__(key) def __getattr__(self, key): print('I\'m in __getattr__ func') return 0 foo = Foo(3) print(foo.a) # 访问存在的属性 print(foo.b) # 访问不存在的属性 # 执行结果如下: I'm in __getattribute__ func 3 I'm in __getattribute__ func I'm in __getattr__ func 0 复制代码
其实我们用 getattr(instance, key)
获取属性值的时候, 内部调用其实是和 .
运算符是一样的!
print(getattr(foo, 'a')) print(getattr(foo, 'b')) # 执行结果如下: I'm in __getattribute__ func 3 I'm in __getattribute__ func I'm in __getattr__ func 0 复制代码
接下来就是 __getitem__
了. 其实重载 __getitem__
实现了容器类, 也就是你可以像字典和列表一样, 通过 instance['key']
或者 instance[index]
获取属性值.
class Poo: def __init__(self, a): self.a = a def __getitem__(self, key): try: val = self.__getattribute__(key) except AttributeError: val = 0 return val a = Poo(3) print(a.a) print(a['a']) print(a['b']) # 执行结果如下: 3 3 0 复制代码
怎么用
知道了它们的不同处之后, 那我们该怎么用呢? 什么时候用哪个呢???
-
__getitem__
:
__getitem__
主要是用于将一个普通的类变成一个容器类, 可以通过像其他容器获取属性值一样获取自定义类的属性值 -
__getattr__
:
__getattr__
主要作用是定制化获取实例中不存在的属性后触发的动作 -
__getattribute__
:
__getattibute__
可以用于阻止获取实例中的某些敏感属性
class Count: def __init__(self,mymin,mymax): self.mymin=mymin self.mymax=mymax self.current=None def __getattribute__(self, item): if item.startswith('cur'): raise AttributeError return object.__getattribute__(self,item) # or you can use ---return super().__getattribute__(item) obj1 = Count(1,10) print(obj1.mymin) print(obj1.mymax) print(obj1.current) # 执行结果如下: 1 10 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-4-2c95d579e6a7> in <module>() 14 print(obj1.mymin) 15 print(obj1.mymax) ---> 16 print(obj1.current) <ipython-input-4-2c95d579e6a7> in __getattribute__(self, item) 7 def __getattribute__(self, item): 8 if item.startswith('cur'): ----> 9 raise AttributeError 10 return object.__getattribute__(self,item) 11 # or you can use ---return super().__getattribute__(item) AttributeError: 复制代码
需要注意的是, 在重载 __getattribute__
的时候, 为了防止无线递归, 我们应该调用基类的 __getattribute__
方法( object.__getattribute__(self, key)
或者 super().__getattribute__(key)
), 而不是直接通过 self.__dict__[key]
这种形式获取属性值.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Python 最会变魔术的魔术方法,我觉得是它
- PHP几种常见魔术方法解析
- PHP反序列化入门之常见魔术方法
- 对于魔术方法 __call, __callStatic 新的认识
- 032.Python魔术方法__new__和单态模式
- 034.Python的__str__,__repr__,__bool__ ,__add__和__len__魔术方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
微商团队管理实战手册
杜一凡 / 人民邮电出版社 / 2015-11 / 45.00元
回顾淘宝,用了10年时间才发展了不到1000万的卖家,再看微商,其仅一年时间就拥有了超过1000万的卖家。进入2015年,微商的发展之路虽有小坎坷,但前景依然被看好。然而任何一个想要做大、做强的微商都要以团队形式来发展,独立的个体只会举步维艰。 本书全面解读微商团队管理的营销书。全书共分为六章,分别从微商团队的商业秘密、微商团队的战略布局、管理基本功、建立高效团队、精通管理工具、未来发展等方......一起来看看 《微商团队管理实战手册》 这本书的介绍吧!