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

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

内容简介: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] 这种形式获取属性值.


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

查看所有标签

猜你喜欢:

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

Coming of Age in Second Life

Coming of Age in Second Life

Tom Boellstorff / Princeton University Press / 2008-04-21 / USD 29.95

The gap between the virtual and the physical, and its effect on the ideas of personhood and relationships, is the most interesting aspect of Boellstorff's analysis... Boellstorff's portrayal of a virt......一起来看看 《Coming of Age in Second Life》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换