【python】魔术方法3
内建函数 |
意义 |
getattr(object, name[, default]) |
通过name返回object的属性值。当属性不存在,将使用default返回,如果没 有default,则抛出AttributeError。 name必须为字符串 |
setattr(object, name, value) |
object的属性存在,则覆盖,不存在,新增 |
hasattr(object, name) |
判断对象是否有这个名字的属性, name必须为字符串 |
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Point(4, 5)
print(p1)
print(p1.x, p1.y)
print(getattr(p1, 'x'), getattr(p1, 'y'), getattr(p1, 'z', 100))
setattr(p1, 'x', 10)
setattr(Point, '__str__', lambda self: "<Point {},{}>" .format(self.x, self.y))
print(p1)
# <__main__.Point object at 0x00000160F149D180>
# 4 5
# 4 5 100
# <Point 10,5>
反射相关的魔术方法
__getattr__() 、 __setattr__() 、 __delattr__() 这三个魔术方法,分别测试这三个方法
__getattr__()
属性不存在时调用,属性的值是函数的返回值
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __getattr__(self, item):
print('getattr~~~')
print(item)
return 100
p1 = Point(4, 5)
print(p1.x)
print(p1.y)
print(p1.z)
# 4
# 5
# getattr~~~
# z
# 100
实例属性查找顺序为:
instance.__dict__ --> instance.__class__.__dict__ --> 继承的祖先类(直到object)的__dict__ ---找不到--> 调用__getattr__()
__setattr__()
设置属性时调用,属性存在,则覆盖,不存在,新增
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __getattr__(self, item):
print('getattr~~~')
print(item)
return 100
def __setattr__(self, key, value):
print('setattr~~~, {}={}' .format(key, value))
p1 = Point(4, 5)
print(p1.x)
print(p1.y)
print(p1.__dict__)
# setattr~~~, x=4
# setattr~~~, y=5
# getattr~~~
# x
# 100
# getattr~~~
# y
# 100
# {}
__setattr__() 方法,可以拦截对实例属性的增加、修改操作,如果要设置生效,需要自己操作实例的 __dict__ 。
__delattr__()
通过实例删除属性,就会尝试调用该魔术方法。
class Point:
Z = 100
def __init__(self, x, y):
self.x = x
self.y = y
def __delattr__(self, item):
print('delattr, {}' .format(item))
p1 = Point(4, 5)
del p1.x
del p1.y
del p1.Z
print(p1.__dict__)
print(Point.__dict__)
del Point.Z
print(Point.__dict__)
# delattr, x
# delattr, y
# delattr, Z
# {'x': 4, 'y': 5}
# {'__module__': '__main__', 'Z': 100, '__init__': <function Point.__init__ at 0x0000019DB320C280>, '__delattr__': <function Point.__delattr__ at 0x0000019DB320C1F0>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None}
# {'__module__': '__main__', '__init__': <function Point.__init__ at 0x0000019DB320C280>, '__delattr__': <function Point.__delattr__ at 0x0000019DB320C1F0>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None}
__getattribute__
实例的所有的属性访问,第一个都会调用 __getattribute__ 方法,它阻止了属性的查找,该方法应该 返回(计算后的)值或者抛出一个AttributeError异常。
它的return值将作为属性查找的结果。
如果抛出AttributeError异常,则会直接调用__getattr__ 方法,因为表示属性没有找到。
class Point:
Z = 100
def __init__(self, x, y):
self.x = x
self.y = y
def __getattr__(self, item):
return 'missing {}' .format(item)
def __getattribute__(self, item):
print(item)
#raise AttributeError('Not Found')
#return self.__dict__[item]
#pass
#return object.__getattribute__(self, item)
return super().__getattribute__(item)
p1 = Point(4, 5)
print(p1.x, p1.y)
print(Point.Z, p1.Z)
print(p1.__dict__)
# x
# y
# 4 5
# Z
# 100 100
# __dict__
# {'x': 4, 'y': 5}
__getattribute__ 方法中为了避免在该方法中无限的递归,它的实现应该永远调用基类的同名方法以 访问需要的任何属性,例如 object.__getattribute__(self, name) 。
注意,除非你明确地知道 __getattribute__ 方法用来做什么,否则不要使用它。
总结
__getattr__() |
当通过搜索实例、实例的类及祖先类查不到属性,就会调用此方法 |
__setattr__() |
通过 . 访问实例属性,进行增加、修改都要调用它 |
__delattr__() |
当通过实例来删除属性时调用此方法 |
__getattribute__ |
实例所有的属性调用都从这个方法开始 |
- 点赞
- 收藏
- 关注作者
评论(0)