本文将介绍如何在不破坏默认行为的情况下覆盖Python中的__getattr__?的详细情况,。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于Python3_
本文将介绍如何在不破坏默认行为的情况下覆盖 Python 中的 __getattr__?的详细情况,。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于Python 3 __getattr__的行为不同于Python 2?、python __getattribute__、__getattr__、__setattr__详解、Python __getattr__、python __getattr__ __setattr__的知识。
本文目录一览:- 如何在不破坏默认行为的情况下覆盖 Python 中的 __getattr__?
- Python 3 __getattr__的行为不同于Python 2?
- python __getattribute__、__getattr__、__setattr__详解
- Python __getattr__
- python __getattr__ __setattr__
如何在不破坏默认行为的情况下覆盖 Python 中的 __getattr__?
我想重写__getattr__
类上的方法来做一些花哨的事情,但我不想破坏默认行为。
这样做的正确方法是什么?
Python 3 __getattr__的行为不同于Python 2?
我需要编写一个实现32位无符号整数的类,就像使用C编程语言一样。我最关心的是二进制转换,但是我通常希望我的班级能够做到:
- 具有相同的界面
int
并可以int
正常使用 - 我的
U32
课程的任何操作(int +U32
,U32
+ int等)也将返回U32 - 是纯Python-我不想使用NumPy,ctypes等。
如在此答案中可以找到的,我得到了一个在Python
2下工作的解决方案。最近,我尝试在Python 3下运行它,并注意到,尽管以下测试代码在旧版本的Python下可以正常工作,但Python 3引发了错误:
class U32: """Emulates 32-bit unsigned int known from C programming language.""" def __init__(self, num=0, base=None): """Creates the U32 object. Args: num: the integer/string to use as the initial state base: the base of the integer use if the num given was a string """ if base is None: self.int_ = int(num) % 2**32 else: self.int_ = int(num, base) % 2**32 def __coerce__(self, ignored): return None def __str__(self): return "<U32 instance at 0x%x, int=%d>" % (id(self), self.int_) def __getattr__(self, attribute_name): print("getattr called, attribute_name=%s" % attribute_name) # you might want to take a look here: # https://stackoverflow.com/q/19611001/1091116 r = getattr(self.int_, attribute_name) if callable(r): # return a wrapper if integer''s function was requested def f(*args, **kwargs): if args and isinstance(args[0], U32): args = (args[0].int_, ) + args[1:] ret = r(*args, **kwargs) if ret is NotImplemented: return ret if attribute_name in [''__str__'', ''__repr__'', ''__index__'']: return ret ret %= 2**32 return U32(ret) return f return rprint(U32(4) / 2)print(4 / U32(2))print(U32(4) / U32(2))
这是错误:
Traceback (most recent call last): File "u32.py", line 41, in <module> print(U32(4) / 2)TypeError: unsupported operand type(s) for /: ''U32'' and ''int''
看来该getattr
技巧在Python 3中根本没有被调用。为什么?如何使此代码在Python 2和3下都能正常工作?
答案1
小编典典您的Python 2解决方案依赖于 旧式类的 行为。如果使类继承自Python 2,则Python 2代码将以与Python3相同的方式失败object
:
class U32(object):
这是因为对于新 类 ,将在 类型 而不是对象本身上查找特殊方法。此行为更改修复了旧模型的一些极端情况。
实际上,这意味着像这样的方法__div__
将直接在U32
自身上查找,而不是在的 实例
上作为属性U32
,并且__getattr__
不会查询该挂钩。
不幸的是,特殊的方法也查找 绕过
任何__getattr__
或__getattribute__
挂钩。请参阅有关特殊方法查找的文档:
除了出于正确性的考虑绕过任何实例属性之外,隐式特殊方法查找通常还绕过该
__getattribute__()
方法,甚至对象的元类也是如此:[…]
__getattribute__()
以这种方式绕过机器为解释器内的速度优化提供了很大的空间,但以牺牲一些特殊方法的灵活性为代价(特殊方法必须在类对象本身上设置,以便由解释器一致地调用)
。
那么,您唯一的选择是在类上动态设置所有特殊方法。一个类装饰器可以在这里做得很好:
def _build_delegate(name, attr, cls, type_): def f(*args, **kwargs): args = tuple(a if not isinstance(a, cls) else a.int_ for a in args) ret = attr(*args, **kwargs) if not isinstance(ret, type_) or name == ''__hash__'': return ret return cls(ret) return fdef delegated_special_methods(type_): def decorator(cls): for name, value in vars(type_).items(): if (name[:2], name[-2:]) != (''__'', ''__'') or not callable(value): continue if hasattr(cls, name) and not name in (''__repr__'', ''__hash__''): continue setattr(cls, name, _build_delegate(name, value, cls, type_)) return cls return decorator@delegated_special_methods(int)class U32(object): def __init__(self, num=0, base=None): """Creates the U32 object. Args: num: the integer/string to use as the initial state base: the base of the integer use if the num given was a string """ if base is None: self.int_ = int(num) % 2**32 else: self.int_ = int(num, base) % 2**32 def __coerce__(self, ignored): return None def __str__(self): return "<U32 instance at 0x%x, int=%d>" % (id(self), self.int_)
我更新了代理功能以正确处理多个参数,并在返回时自动强制返回到您的自定义类int
。
python __getattribute__、__getattr__、__setattr__详解
__getattribute__
官方文档中描述如下:
该方法可以拦截对对象属性的所有访问企图,当属性被访问时,自动调用该方法(只适用于新式类)。因此常用于实现一些访问某属性时执行一段代码的特性。
需要注意的是,正式由于它拦截对所有属性的访问(包括对__dict__的访问),在使用中要十分小心地避开无限循环的陷阱。在__getattribute__方法中访问当前实例的属性时,唯一安全的方式是使用基类(超类) 的方法__getattribute__(使用super)。例如:
通过上图中的代码示例可以看出,一旦实现了__getattribute__方法,所有通过对象访问的属性(包括类属性)都会被拦截,而直接通过类访问类属性则不会。
注意:当访问的属性不存在并重载(覆盖基类对某方法的默认实现)了__getattribute__方法时,该方法不会主动抛出AttributeError异常。上图中捕获的AttributeError异常,是由基类__getattribute__方法实现并抛出。
常见的错误用法示例:
在实现__getattribute__方法时访问对象自身的属性,程序陷入无限循环直到崩溃。
__getattr__
官方文档描述如下:
__getattr__方法的自动执行,需要满足两个条件:一是访问对象属性;二是触发AttributeError异常。代码示例如下:
上图中,调用不存在的job属性首先调用__getattribute__方法(如果该方法未定义,会调用基类的__getattribute__方法),触发AttributeError异常并自动捕获,然后才调用__getattr__方法。
错误用法示例如下:
重载了__getattribute__方法,却没有主动抛出AttributeError异常的机制,或者抛出一个其它类型的异常,__getattr__方法都不会执行。
__setattr__
试图给属性赋值时自动调用该方法,例如:
之所以会执行三次print函数,是因为在__init__方法中,对象A初始化时给属性name和age赋值时,触发了__setattr__方法。使用该方法是同样需要十分小心避免无限循环陷阱。
错误用法示例如下:
可以看出,在__setattr__方法中,不能直接给属性赋值,而通常的做法是使用__dict__魔法属性。__dict__属性是一个字典,所有的实例属性都存储在这个字典中,而修改__dict__字典中的键值对成员不会触发__setattr__方法,这里应注意与直接修改__dict__的值的区别。
注意:如果定义__setattr__方法的同时定义了__getattribute__方法,那么在修改__dict__字典中的键值对时,由于调用了self.__dict__属性,同样会触发__getattribute__方法,使用时应格外小心。代码示例如下:
上图示例代码中,每调用一次__setattr__就会调用一次__getattribute__。
注意赋值语句与属性调用的区别:self.__dict__ = {}是赋值语句,不会触发__getattribute__方法,但触发__setattr__方法;self.__dict__[name] = value语句,先调用self.__dict__属性,得到dict对象后再修改其成员,因此会触发__getattribute__方法。
以上。
Python __getattr__
python __getattr__ __setattr__
class Rectangle:
def __init__(self):
self.width = 0
self.height = 0
def __setattr__(self, key, value):
if key == ''size'':
self.width, self.height = value
else:
self.__dict__[key] = value
def __getattr__(self, item):
if item == ''size'':
return self.width, self.height
else:
return self.__dict__[item]
tR = Rectangle()
tR.__setattr__(''size'',(1,3))
print(tR.__getattr__(''size''))
resule:
(1, 3)
我们今天的关于如何在不破坏默认行为的情况下覆盖 Python 中的 __getattr__?的分享就到这里,谢谢您的阅读,如果想了解更多关于Python 3 __getattr__的行为不同于Python 2?、python __getattribute__、__getattr__、__setattr__详解、Python __getattr__、python __getattr__ __setattr__的相关信息,可以在本站进行搜索。
本文标签: