python总结(五):__get__、__getattr__、__getitem__、__getattribute__之间的差异与联系


python的一切数据都是对象,包括函数、基本数据类型、自定义数据类型等等,这其中最复杂的就是对象内部存储的数据结构(引用),包括类属性、数据描述符、实例属性及非数据描述符,不仅它们的优先级不一样,而且它们的回调函数也存在很大的差异,这也是本文需要阐述的地方。

如果以前有过Javascript的编程经验,初上Python肯定会对“.”运算符与“[]”之间的差异难以理解,它们不仅不能替换,而且完全不相关,如下:

mem = {'username': 'yiifaa'}
# 无法通过.运算符进行计算
mem.username
# 声明String
name = str('yiifaa')
# 无法使用“[]”运算符
name['upper']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1. 为实例添加“[]”运算符支持

这也是“_ getattribute_”与“_ getitem_”的最大差异,示例如下: 
1. “_ getattribute_”只适用于所有的“.”运算符; 
2. “_ getitem_”只适用于所有的“[]”运算符;

class Employee(object):

    def __init__(self, username, age):
        self.username = username
        self.age = age

    def __getattribute__(self, attr):
        return super(Employee, self).__getattribute__(attr)

    def __getitem__(self, attr):
        return super(Employee, self).__getattribute__(attr)

em = Employee('yiifaa', 32)
print em.username
#   现在支持“[]”运算符
print em['username']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

通过实现“_ getitem_”回调接口,现在Employee可以支持“[]”运算符。

2. 避免语法错误错误

在对象属性的调用中,如果没有调用了不存在的属性,则Python解释器会报错,如下:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'length'
  • 1
  • 2
  • 3

通过覆盖实现“_ getattr_”回调接口可以解决此问题,如下:

#   直接返回空对象,将此方法添加到类Employee的声明中
def __getattr__(self, attr):
    return None

# 现在调用不存在的属性也不会报错
print em.company
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

那“_ getattribute_”与“_ getattr_”的最大差异在于: 
1. 无论调用对象的什么属性,包括不存在的属性,都会首先调用“_ getattribute_”方法; 
2. 只有找不到对象的属性时,才会调用“_ getattr_”方法;

3. 将对象作为数据描述符

这就是“_ get_”的作用了,将整个对象都作为数据描述符,但是请记住,要想““_ get_””作为数据描述符,那么此对象只能作为类属性,作为实例属性则无效,如下:

class Dept(object):

      def __init__(self, name):
          self.name = name

      # target是拥有此属性的对象
      def __get__(self, target, type=None):
        # 默认返回self与obj都可以
        return 'Dept'

class Company(object):
    #   一定要作为类属性,作为实例属性无效
    dept = Dept('organ')

# 现在的测试结果
x = Company()
#   返回True
print type(x.dept) == str
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

4. 获取对象属性数据的三种方法

对象的所有属性都存储在“_ dict_”中(启用了“_ slots_”除外),所以访问对象的属性数据有如下三种方法:

print yiifaa.name
print yiifaa.__dict__['name']
print getattr(yiifaa, 'name')
  • 1
  • 2
  • 3

结论

每个以“__ get”为前缀的方法都是获取对象内部数据的钩子,但名称不一样,用途也存在较大的差异,只有在实践中理解它们,才能真正掌握它们的用法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
`__getattr__`和`__getattribute__`是Python中特殊的方法,用于处理对象的属性访问和获取。 `__getattr__`用于在对象实例的属性不存在时被调用,通常在动态获取属性的情况下使用。当我们尝试访问一个对象上不存在的属性时,Python解释器会自动调用`__getattr__`方法。我们可以在这个方法中定义对不存在属性的处理逻辑,比如返回默认值或者触发异常。 下面是一个示例: ``` class MyClass: def __getattr__(self, name): return f"Attribute {name} does not exist." obj = MyClass() print(obj.some_attr) # Output: Attribute some_attr does not exist. ``` `__getattribute__`用于在对象实例的属性被访问时被调用。与`__getattr__`不同,`__getattribute__`会在所有属性访问上被调用,无论属性是否存在。我们可以通过在`__getattribute__`方法中自定义属性访问的行为,比如在访问属性前执行一些操作或返回特定的值。 下面是一个示例: ``` class MyClass: def __getattribute__(self, name): print(f"Accessing attribute {name}") return super().__getattribute__(name) obj = MyClass() print(obj.some_attr) # Output: # Accessing attribute some_attr # None ``` 注意,使用`__getattribute__`时需要谨慎,因为在方法内部访问同个实例的其他属性时可能会触发无限递归调用。在这种情况下,可以通过使用`super()`来避免无限递归。 综上所述,`__getattr__`和`__getattribute__`是Python中用于处理对象属性访问和获取的特殊方法,分别用于处理不存在属性和所有属性的访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Terry_dong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值