python: 理解 __getattr__, getattr ,

本文详细解释了Python中getattr和__getattr__函数的使用方法,并通过实例展示了如何利用这两个函数来获取对象的属性值。文章还介绍了如何区分对象属性与字典键值的不同获取方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下是我的个人理解,如有错误,务必指正,不胜感激!


首先,我们看getattr,顾名思义,得到属性。它的全部应该是getattr(object,“attribution”,None),一般情况我们这么用getattr(object,name)

它类似于得到object.attribution的值。

getattr的用法:

比如:

>>> class test:
...     cal=1
...
>>> getattr(test,"cal")
1
>>> test.cal
1
>>>

因为,cal是test的一个属性,所以,上面的结果你是可以理解。那么,如何看一个对象的属性呢?

dir("对象") 就可以了。

>>> dir(test)
['__doc__', '__module__', 'cal']
看看下面的例子:
>>> t={}
>>> t['a'] = "hello"
>>> t['b'] = "world"
>>> getattr(t,"a")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>

AttributeError: 'dict' object has no attribute 'a'

 可能你的意图是利用getattr得到t[a]的值,但是,出现了错误,为什么?

因为a不是t的属性

>>> dir(t)
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

看到了吧,这里面没有“a”, __str__是t的属性。

>>> getattr(t,"__str__")()
"{'a': 'hello', 'b': 'world'}"
>>> t.__str__()
"{'a': 'hello', 'b': 'world'}"

__getattr__的用法:

__getattr__()是仅当属性不能在实例的__dict__或它的类(类的__dict__),或父类其__dict__中找到时,才被调用。一般在代码中包含一个对getattr()內建函数的调用

每一个类都会用一个字典,把它包含的属性放到自己的字典里(这是内建的),


>>> dir(test)

['__doc__', '__module__', 'cal']
>>> test.__dict__

{'__module__': '__main__', '__doc__': None, 'cal': 1}

看看下面的例子:

#!/usr/bin/env python
class WrapMe(object):
    def __init__(self,obj):
        print "I am in init"
        self.__data = obj
    def get(self):
        print "I am in get"
        return self.__data
    def __repr__(self):
        print "I am in repr"
        return 'self.__data'
    def __str__(self):
        print "I am in str"
        return str(self.__data)
    def __getattr__(self, attr):                                                                                                                                                                             
        print "I am in getattr"
        return getattr(self.__data, attr)

if __name__ == "__main__":
    wcomplex = WrapMe(3.5+4.2j)
    print  wcomplex
    print wcomplex.real    
    print wcomplex.get()

$./attr.py

I am in init
I am in str
(3.5+4.2j)
I am in getattr
3.5
I am in get
(3.5+4.2j)

我们分析程序如下:

wcomplex = WrapMe(3.5+4.2j)

这时候输出应为:I am in init

print  wcomplex

这时候调用了__str__ 函数

 print wcomplex.real
我们知道,real不是实例wcomplex的属性。这时候,__getattr__将被调用。

def __getattr__(self, attr):                                                                                                                                                                             
        print "I am in getattr"
        return getattr(self.__data, attr)

这时候,调用getattr(),也就是self.__data.attr=>(3.5+4.2j).real 得到实部3.5。

 print wcomplex.get()

因为,get方法是wcomplex的属性。所以,直接调用了get()方法。没有调用__getattr__()

### Python 中 `__getattr__` 方法的用法 在 Python 的类定义中,`__getattr__` 是一种特殊的方法,用于处理访问不存在的属性的情况。当尝试访问对象的一个未定义属性时,如果该类实现了 `__getattr__` 方法,则会调用此方法来动态返回值或执行特定逻辑[^1]。 以下是关于 `__getattr__` 方法的一些重要特性和使用场景: #### 特性描述 - 当通过点号操作符(`.`)访问一个实例的属性而找不到对应名称时,Python 会在抛出 `AttributeError` 前自动调用 `__getattr__` 方法。 - 需要注意的是,只有在常规属性查找失败的情况下才会触发 `__getattr__` 方法。因此,在类中显式定义的属性不会进入这个机制[^2]。 #### 使用示例 下面是一个简单的例子展示如何自定义行为以应对未知属性请求: ```python class DynamicAttributes: def __init__(self, initial=None): if initial is None: self.data = {} else: self.data = dict(initial) def __getattr__(self, name): """Called when an attribute lookup has not found the attribute in the usual places.""" try: return self.data[name] except KeyError as e: raise AttributeError(f"No such attribute: {e}") example = DynamicAttributes({"key": "value"}) print(example.key) # 输出 'value' # 下面这行将会引发 AttributeError 因为字典里没有对应的键 # print(example.nonexistent_key) ``` 在这个例子中,我们创建了一个名为 `DynamicAttributes` 的类,它允许存储任意数量的关键字参数作为内部数据结构的一部分,并且可以通过普通的点记法访问这些关键字所代表的数据项。如果没有找到指定的名字,则会抛出异常表明缺少这样的特性[^3]。 另外需要注意一点区别:虽然两者都涉及到了获取成员的操作,但是 `__getattribute__` 函数几乎适用于所有的属性检索过程;相比之下,`__getattr__` 只有在标准途径无法定位到目标的时候才被激活[^4]。 #### 单例模式中的应用举例 有时可以利用 `__getattr__` 来辅助构建某些设计模式下的解决方案,比如单例模式。尽管这里给出的例子主要依赖于装饰器完成任务,但我们同样能够借助类似的思路结合 `__getattr__` 达成目的[^5]: ```python class SingletonMeta(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: instance = super().__call__(*args, **kwargs) cls._instances[cls] = instance return cls._instances[cls] def __getattr__(cls, item): if hasattr(SingletonMeta._instances.get(cls), item): return getattr(SingletonMeta._instances.get(cls), item) raise AttributeError("No such attribute exists.") class MySingleton(metaclass=SingletonMeta): pass first_instance = MySingleton() second_instance = MySingleton() assert first_instance is second_instance ``` 在此案例中展示了另一种形式的单例实现方式——元编程技术。其中也体现了对于非正式存在的字段查询进行了重定向处理的方式[^6]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值