Python 魔法方法之自定义实例属性
Python 魔法方法系列 让你的代码更加 pythonic
__getattribute__
object.__getattribute__(self, name)
方法用于自定义实例属性的访问,使用时需注意:
- 该魔法方法会在访问实例的任何属性时无条件调用。
- 重写该魔法方法时需要返回一个属性值或是触发
AttributeError
异常。 - 当定制类继承
Object
时,同时也会继承该魔法方法,但它没有执行任何操作。
示例代码:
class Karen:
age = '30'
def __getattribute__(self, name):
print('__getattribute__')
return None
def holdon(self):
print('I am protector')
p = Karen()
print(p.age)
print(p.sex)
print(p.holdon)
执行结果:
__getattribute__
None
__getattribute__
None
__getattribute__
None
可以看出,无论是访问 Karen
已有的属性 age
和方法 holdon
,还是没有的属性 sex
,都会执行 __getattribute__
方法,并返回该方法的返回值。
当需要其返回属性原有的值的时候,可以返回基类 (Object) 的 __getattribute__
方法并传递相同的 name
参数:
...
def __getattribute__(self, name):
print('__getattribute__')
return super().__getattribute__(name)
...
p = Karen()
print(p.age)
p.holdon()
执行结果:
__getattribute__
30
__getattribute__
I am protector
另外要注意避免自定义该方法时可能产生的无限递归:
-
示例一
... def __getattribute__(self, name): print('__getattribute__') if name == "sex": return 'w' else: return self.holdon() ... p = Karen() p.protector
执行结果:
RecursionError: maximum recursion depth exceeded while calling a Python object
-
示例二
... def __getattribute__(self, name): print('__getattribute__') if name == "holdon": return self.holdon() return super().__getattribute__(name) ... p = Karen() p.holdon
执行结果:
__getattribute__ 30 __getattribute__ ... RecursionError: maximum recursion depth exceeded while calling a Python object
__getattr__
object.__getattr__(self, name)
方法同样用于自定义实例属性的访问,使用时需注意:
- 该魔法方法会在默认属性访问失败触发
AttributeError
时被调用。- 该魔法方法因参数
name
不是实例属性而触发AttributeError
- 该魔法方法因参数
name
不是类树中用于self
的属性而触发AttributeError
- 因
name.__get__()
触发AttributeError
- 该魔法方法因参数
- 重写该方法时需要返回一个属性值或是触发
AttributeError
异常。 - 当定制类继承
Object
时,同时也会继承object.__getattribute__(self, name)
,但它没有执行任何操作。
__setattr__
object.__setattr__(self, name, value)
方法用于自定义实例属性的赋值,使用时需注意:
- 该魔法方法会在尝试给实例属性赋值时被调用。
- 如果需要给实例属性赋值,则还需要调用基类的同名方法。
示例代码:
class Karen:
age = 30
name = 'Karen'
def __setattr__(self, key, value):
print('__setattr__')
if key == 'age':
print('age cannot be modified')
else:
print('assign value via Object.__setattr__(self, key, value)')
super().__setattr__(key, value)
p = Karen()
p.age = 'Any'
p.name = 'Karen1'
print(p.age)
print(p.name)
执行结果:
__setattr__
age cannot be modified
__setattr__
assign value via Object.__setattr__(self, key, value)
30
Karen1
__delattr__
object.__delattr__(self, name)
方法用于自定义实例属性的删除,使用时需注意:
- 该魔法方法会在
del obj.name
或delattr(obj, name)
时被调用。 - 该方法仅当上述动作有意义时才应被实现。
示例代码:
class Karen:
Katherine = True
Holdon = True
Karen = True
def __delattr__(self, name):
print('__delattr__')
p = Karen()
del p.Katherine
delattr(p, 'Katherine')
执行结果:
__delattr__
__delattr__
__dir__
object.__dir__(self)
在对实例调用 dir()
时被调用。该魔法方法必须返回一个 sequence
。dir()
会将该 sequence
转换成列表并进行排序。
参考来源:
https://docs.python.org/3/reference/datamodel.html#special-method-names