__new__
是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。
__init__
是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值。
故而“ 本质上 ”来说,__new__
()方法负责创建实例,而__init__
()仅仅是负责实例属性相关的初始化而已,执行顺序是,先new后init。
class Student(object): def __new__(cls,*args,**kwargs): print('我是new函数!') #这是为了追踪new的执行过程 print(type(cls)) #这是为了追踪new的执行过程 return object.__new__(cls) #调用父类的(object)的new方法,返回一个Student实例,这个实例传递给init的self参数 def __init__(self,name,age): self.name=name self.age=age print('我是init') def study(self): print('我爱学习!') if __name__=='__main__': s=Student('张三',25) print(s.name) print(s.age) s.study()
运行结果为:
我是new函数! <class 'type'> 我是init 张三 25 我爱学习!
1.2. 属性访问控制
通常情况下,我们在访问类或者实例对象的时候,会牵扯到一些属性访问的魔法方法,主要包括:
① getattr (self, name): 访问不存在的属性时调用
② getattribute (self, name):访问存在的属性时调用(先调用该方法,查看是否存在该属性,若不存在,接着去调用①)
③ setattr (self, name, value):设置实例对象的一个新的属性时调用
④ delattr (self, name):删除一个实例对象的属性时调用 一个例子
class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value): print('----> from setattr') # self.key=value #这就无限递归了,你好好想想 self.__dict__[key]=value #应该使用它 def __delattr__(self, item): print('----> from delattr') # del self.item #无限递归了 self.__dict__.pop(item) def __getattribute__(self, item): print('----> __getattribute__') return super().__getattribute__(item) #__setattr__添加/修改属性会触发它的执行 f1=Foo(10) print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 f1.z=3 print(f1.__dict__) #__delattr__删除属性的时候会触发 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作 del f1.a print(f1.__dict__) #__getattr__只有在使用点调用属性且属性不存在的时候才会触发 f1.xxxxxx
输出
----> from setattr ----> __getattribute__ ----> __getattribute__ {'y': 10} ----> from setattr ----> __getattribute__ ----> __getattribute__ {'y': 10, 'z': 3} ----> __getattribute__ ----> from delattr ----> __getattribute__ ----> __getattribute__ {'y': 10, 'z': 3} ----> __getattribute__ ----> from getattr:你找的属性不存在
注意,调用
self.__dict__[key]=value
会触发
def __getattribute__(self, item): print('----> __getattribute__') return super().__getattribute__(item)
因为 虽然是要给字典self.__dict__
添加键值对,其中隐含着首先获得self.__dict__
。 另外__getattribute__
需要返回super().__getattribute__(item)
,否则函数默认返回None,报错。