实例instance通过instance.name访问属性name,只有当属性name没有在实例的__dict__或它构造类的dict或基类的dict中没有找到,才会调用__getattr__。当属性name可以通过正常机制追溯到时,getattr是不会被调用的。如果在getattr(self, attr)存在通过self.attr访问属性,会出现无限递归错误。
class Foo(): c = 1 def __init__(self,name): self.name = name def __getattr__(self, item): print(item) # self.item 无限递归错误 print("__getattr__") def sing(self): print("sing") foo = Foo("safly") print(foo.__dict__) print(foo.a)输出如下:
{'name': 'safly'} a __getattr__ None from threading import get_ident,Thread import time class Local(object): storage = {} def __setattr__(self, k, v): print("__setattr__", k,v) ident = get_ident() if ident in Local.storage: Local.storage[ident][k] = v else: Local.storage[ident] = {k: v} def __getattr__(self, k): print("__getattr__",k) ident = get_ident() return Local.storage[ident][k] obj = Local() def task(arg): obj.val = arg print(obj.val) for i in range(10): t = Thread(target=task,args=(i,)) t.start()输出如下:
E:\python\python_sdk\python.exe "C:/Users/67334/Documents/Tencent Files/673346821/FileRecv/day123/safly.py" __setattr__ val 0 __getattr__ val 0 __setattr__ val 1 __getattr__ val 1 __setattr__ val 2 __getattr__ val 2 __setattr__ val 3 __getattr__ val 3 __setattr__ val 4 __getattr__ val 4 __setattr__ val 5 __getattr__ val 5 __setattr__ val 6 __getattr__ val 6 __setattr__ val 7 __getattr__ val 7 __setattr__ val 8 __getattr__ val 8 __setattr__ val 9 __getattr__ val 9 Process finished with exit code 0实例instance通过instance.name访问属性name,__getattribute__方法一直会被调用,无论属性name是否追溯到。如果类还定义了getattr方法,除非通过__getattribute__显式的调用它,或者getattribute方法出现AttributeError错误,否则getattr方法不会被调用了。如果在getattribute(self, attr)方法下存在通过self.attr访问属性,会出现无限递归错误。 如下所示,ClassA中定义了getattribute方法,实例insA获取属性时,都会调用getattribute返回结果,即使是访问__dict__属性
class Foo(): c = 1 def __init__(self,name): self.name = name def __getattr__(self, item): print(item) # self.item 无限递归错误 print("__getattr__") def __getattribute__(self, item): print(item) # self.item 无限递归错误 print("__getattribute__") def sing(self): print("sing") foo = Foo("safly") print(foo.__dict__) print(foo.a)输出如下:
E:\python\python_sdk\python.exe E:/python/py_dev/python/django_dev/app08/tests.py __dict__ __getattribute__ None a __getattribute__ None Process finished with exit code 0示例
class Foo(): c = 1 def __init__(self,name): self.name = name def __getattr__(self, item): print(item) # self.item 无限递归错误 print("__getattr__") def __getattribute__(self, item): print(item) # self.item 无限递归错误 print("__getattribute__") def sing(self): print("sing") foo = Foo("safly") print(Foo.__dict__)输出如下:
{'__module__': '__main__', 'c': 1, '__init__': <function Foo.__init__ at 0x055919C0>, '__getattr__': <function Foo.__getattr__ at 0x05591978>, '__getattribute__': <function Foo.__getattribute__ at 0x05591930>, 'sing': <function Foo.sing at 0x05591810>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}如下代码
class Foo(): def __init__(self,name): self.name = name def __getattr__(self, item): print("__getattr__", item) def __getattribute__(self, item): print("__getattribute__",item) raise AttributeError() foo = Foo("safly") foo.a输出
__getattribute__ a __getattr__ a如果类自定义了setattr方法,当通过实例获取属性尝试赋值时,就会调用setattr。 常规的对实例属性赋值,被赋值的属性和值会存入实例属性字典dict中。
class Foo(): def __init__(self,name): self.name = name def __setattr__(self, key, value): print("__getattr__", key, value) foo = Foo("safly") foo.a=1 Foo.b = 1输出如下:
E:\python\python_sdk\python.exe E:/python/py_dev/python/django_dev/app08/tests.py __getattr__ name safly __getattr__ a 1在看一个例子
class Foo(): def __init__(self,name): self.name = name def __setattr__(self, key, value): print("__getattr__", key, value) foo = Foo("safly") foo.a=1 print(foo.__dict__)输出如下:
__getattr__ name safly __getattr__ a 1 {}继续看示例
class Foo(): def __init__(self,name): self.name = name def __setattr__(self, key, value): print("__getattr__", key, value) self.__dict__[key] = value foo = Foo("safly") foo.a=1 print(foo.__dict__) print(Foo.__dict__)输出如下:
E:\python\python_sdk\python.exe E:/python/py_dev/python/s8day93/app01/tests.py getattr name safly getattr a 1 {‘name’: ‘safly’, ‘a’: 1}
{'__module__': '__main__', '__init__': <function Foo.__init__ at 0x058129C0>, '__setattr__': <function Foo.__setattr__ at 0x05812978>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}输出如下:
创建类之前 创建类之后 创建类之前 创建类之后 class MyType(type): def __init__(self,*args,**kwargs): print('创建类之前') super(MyType,self).__init__(*args,**kwargs) print('创建类之后') def with_metaclass(arg): return MyType('Base',(arg,),{}) # class Base(object,metaclass=MyType): pass class Foo(with_metaclass(object)): CITY = "bj" def func(self, x): return x + 1输出如下:
创建类之前 创建类之后 创建类之前 创建类之后