魔术方法(一) __getattribute__ VS __getattr__ VS __getitem___

栏目: Python · 发布时间: 5年前

内容简介:Python 中有三个看上去非常相似的魔法方法:首先来看看但是, 如果你在定义类的时候实现了

Python 中有三个看上去非常相似的魔法方法: __getattribute__ , __getattr__ , __getitem___ , 就是前面这仨哥们儿了.

不同之处

首先来看看 __ getattribute____getattr__ , 这俩在一定程度上有先后调用的关系. 简单来说, 在用 . 运算符获取某个实例的属性值的时候, Python 解释器会首先调用 __getattribute__ , 如果该实例中有需要获取的属性值, 就返回属性值, 如果没有, 则会抛出 AttributeError .

魔术方法(一) __getattribute__ VS __getattr__ VS __getitem___
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

复制代码

怎么用

知道了它们的不同处之后, 那我们该怎么用呢? 什么时候用哪个呢???

  1. __getitem__ :
    __getitem__ 主要是用于将一个普通的类变成一个容器类, 可以通过像其他容器获取属性值一样获取自定义类的属性值
  2. __getattr__ :
    __getattr__ 主要作用是定制化获取实例中不存在的属性后触发的动作
  3. __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] 这种形式获取属性值.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

再看电商

再看电商

黄若 / 电子工业出版社 / 2014-7-1 / CNY 39.00

电商行业在中国经历了十年的高速增长。如果说十年前的网上购物是新鲜潮人的尝试的话,那么今天几亿网购人群的规模,零售市场18,000亿人民币的年交易额,正催生着一个改变人们生活习惯的全新行业。互联网正在从各个维度重新定义生产、品牌、娱乐、传播、消费,电商毫无疑问的在购物领域影响着越来越多人的生活。同时,这个行业连年亏损,顾客服务良莠不齐,也受到广泛关注。作者从地面零售到电子商务,从跨国公司高管到管理民......一起来看看 《再看电商》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具