在python中,有一些内置好的特定的方法,这些方法在进行特定的操作时会自动被调用,称之为魔法方法,下面介绍几种常见的魔法方法。
初始化函数,在创建实例对象为其赋值时使用,在__new__之后,__init__必须至少有一个参数self,就是这个__new__返回的实例,__init__是在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。
很多人认为__init__是类的构造函数,其实不太确切,__init__更多的是负责初始化操作,相当于一个项目中的配置文件,__new__才是真正的构造函数,创建并返回一个实例对象,如果__new__只调用了一次,就会得到一个对象。继承自object的新式类才有__new__这一魔法方法,__new__至少必须要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供,__new__必须要有返回值,返回实例化出来的实例(很重要),这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例,若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行。__new__是唯一在实例创建之前执行的方法,一般用在定义元类时使用。
创建对象的步骤:
a、首先调用__new__得到一个对象
b、调用__init__为对象添加属性
c、将对象赋值给变量
下面来看一个结合__init__和__new__两个魔法方法的例子:
从运行结果可以看出,__new__中的参数cls和B的id是相同的,表明__new__中默认的参数cls就是B类本身,而在return时,并没有正确返回当前类cls的实例,而是返回了其父类A的实例,因此__init__这一魔法方法并没有被调用,此时__new__虽然是写在B类中的,但其创建并返回的是一个A类的实例对象。现在将return中的参数A变为cls,再来看一下运行结果:
可以看出,当__new__正确返回其当前类cls的实例对象时,__init__被调用了,此时创建并返回的是一个B类的实例对象。
在将对象转换成字符串 str(对象) 测试的时候,打印对象的信息,__str__方法必须要return一个字符串类型的返回值,作为对实例对象的字符串描述,str__实际上是被print函数默认调用的,当要print(实例对象)时,默认调用__str__方法,将其字符串描述返回。如果不是要用str()函数转换。当你打印一个类的时候,那么print首先调用的就是类里面的定义的__str。 类似java中的 toString()。
对象在程序运行结束之后进行垃圾回收的时候调用这个方法,来释放资源。此时,此方法是被自动调用的。除非有特殊要求,一般不要重写。在关闭数据库连接对象的时候,可以在这里,释放资源。
属性访问拦截器,在访问实例属性时自动调用。在python中,类的属性和方法都理解为属性,且均可以通过__getattribute__获取。当获取属性时,相当于对属性进行重写,直接return object.getattribute(self, *args, **kwargs)或者根据判断return所需要的重写值,如果需要获取某个方法的返回值时,则需要在函数后面加上一个()即可。如果不加的话,返回的是函数引用地址。下面看一个例子:
在创建实例对象s并对其初始化的时候,subject1的值设置为‘python’,subject2的值设置为‘cpp’,在访问s的subject1属性时,因为Test类对object类中的__getattribute__方法进行了重写,所以在调用此方法时,首先对要访问的属性做一个拦截和判断,此时__getattribute__方法中的参数obj对应的是要访问的属性,若要访问subject1属性,则对该属性进行重写,返回了一个不同的字符串,我们可以看到,在初始化时,subject1 的值为‘python’,而在访问subject1这个属性时,返回的值是’redirect python’,而在访问subject2时,则调用其父类中的__getattribute__方法,返回正常的subject2属性的值。当然,在访问类的方法属性时,也可以通过重写__getattribute__的方法对其进行重写。
获取指定类的所有父类构成元素,使用方法为类名.bases
显示指定类的所有继承脉络和继承顺序,假如这个指定的类不具有某些方法和属性,但与其有血统关系的类中具有这些属性和方法,则在访问这个类本身不具有的这些方法和属性时,会按照__mro__显示出来的顺序一层一层向后查找,直到找到为止。
将一个py文件作为模块导入时,其中if name == "main"以上的类、方法、函数等都能被导入,但某些方法可能只是用来做测试用的,不希望也不建议被导入,可以用__all__=[‘函数名或方法名’]的方式限制一下哪些函数或方法可以被导入,即[]中的函数名或方法名可以被导入。但是需要强调的是,*__all__魔法方法只针对通过 from xx import 这种导入方式有效。
文章转载至:https://www.jianshu.com/p/3f4786b33f34