#反射魔术方法
class Base:
n = 0
class Point(Base):
z = 6
d = {}
def __init__(self,x,y):
self.x = x
self.y = y
self.z = 100
def show(self):
print(self.x,self.y)
def __getattr__(self,item): # 碰见AttributeError进入,哪怕AttributeError被捕获,也会进入此魔术方法
print("getattr is {}".format(item)) # 参数item为字符串,所以可以直接使用内建的反射方法
# setattr(p,'d',100)
# return getattr(p,'d',100) # 未抛AttributeError,返回100,但是依然进入__getattr__的魔术方法
# return self.d[item] # item是字典的key
return 1
def __setattr__(self, key, value): # 实例通过.号设置属性,例如在初始化函数中self.x = x,就会调用__setattr__()
print('key is {},value is {}'.format(key,value)) #key,value为字符串,所以可以直接setattr反射方法
# self.d[key] = value # 将属性放在了类属性字典上,可以通过这样方式,让实例字典上没有任何信息
# return setattr(self,key,value) # 反射的魔术方法中,使用同名的内建反射方法,多数情况下都是递归,所以请使用self.__dict__添加属性
self.__dict__[key] = value # 这个不是属性赋值,而是先方法self.__dict__属性,然后在__dict__组成key-value对
# print('setattr',self.__dict__)
def __delattr__(self,item): # 实例删除属性的时候进入,不会影响类删除自己的实例,且传入的item参数,实例只会在自己的字典中找,没有抛错
print('can not del {}'.format(item))
# return delattr(p,'y') # 反射的魔术方法中,使用同名的内建反射方法,递归,不要使用
self.__dict__.pop(item) # 建议使用这种方法
def __getattribute__(self,item): # 属性访问第一站,如果定义此魔术方法,实例所有的属性调用都从这个方法开始
print('getattribute : {} , type is {}'.format(item,type(item)))
# raise AttributeError
# return self.__dict__[item] # 属性访问就是调用此魔术方法,递归
# return object.__getattribute__(self,item)
return super(Point,self).__getattribute__(item) # 等价super().__getattribute__(item)
p = Point(4,5)
print(p.s)