内容简介: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__魔术方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
松本行弘的程序世界
松本行弘 / 柳德燕、李黎明、夏倩、张文旭 / 人民邮电出版社 / 2011-8 / 75.00元
《松本行弘的程序世界》是探索程序设计思想和方法的经典之作。作者从全局的角度,利用大量的程序示例及图表,深刻阐述了Ruby编程语言的设计理念,并以独特的视角考察了与编程相关的各种技术。阅读《松本行弘的程序世界》不仅可以深入了解编程领域各个要素之间的关系,而且能够学到大师的思考方法。 《松本行弘的程序世界》面向各层次程序设计人员和编程爱好者,也可以供相关技术人员参考。一起来看看 《松本行弘的程序世界》 这本书的介绍吧!