python魔法方法
1.__init__:
初始化函数,在创建实例对象为其赋值时使用,在__new__方法之后。__init__必须至少有一个参数__self__,就是这个__new__返回的实例,__init__是在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
class Person:
def __init__(self, name):
self.name = name
p1 = Person("liang")
2.__new__:
很多人认为__init__是类的构造函数,其实不太确切,__init__更多的是负责初始化操作,相当于一格项目中的配置文件,__new__才是真正的构造函数,创建并返回一个实例对象,如果__new__只调用了一次,就会得到一格对象。==继承自object的新式类才有__new__这一魔法方法,==__new__至少必须要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供,==__new__必须要有返回值,返回实例化出来的实例(很重要),==这点在自己实现__new__时要特别注意,可以返回父类__new__出来的实例,或者直接是object的__new__出来的实例,若__new__没有正确返回当前类cls的实例,那么__init__是不会被调用的,即使是父类的实例也不行。__new__是唯一在实例初始化之前执行的方法,一般用在定义元类时使用。
创建对象的步骤
a) 调用__new__得到一个对象
b) 调用__init__为对象添加属性
c) 将对象赋值给变量
下面是结合了__new__和__init__两个魔法方法的例子
class A:
pass
class B:
def __new__(cls):
print(1, "__new__被调用")
print(2, id(cls))
return object.__new__(A)
def __init__(self):
print(3, "__init__被调用")
b = B()
print(4, b)
print(5, type(b))
print(6, id(A))
print(7, id(B))
输出结果
1 __new__被调用
2 2874488523832
4 <__main__.a object at>
5
6 2874488518168
7 2874488523832
从输出的结果可以看出,__new__中的参数cls和B的id是相同的,表明__new__中默认的参数cls就是B类本身,而在返回时,并没有正确返回当前类cls的实例,而是返回了其父类A的实例,因此__init__这一魔法方法并没有被调用,此时__new__虽然是写在B类中的,但其创建并返回的是一个A类的实例对象。
接下来将return中的参数A改为cls,再看一下运行结果
1 __new__被调用
2 1337840903624
3 __init__被调用
4 <__main__.b object at>
5
6 1337840910232
7 1337840903624
可以看出,当__new__正确返回其当前类cls的实例对象时,__init__被调用了,此时创建并返回的是一个B类的实例对象。
3.__class__:获得已知对象的类
class A:
pass
a = A()
print(a.__class__)
打印的结果
__class__的作用
class A:
count = 0
def add_count(self):
self.__class__.count += 1
a = A()
a.add_count()
print(a.count)
b = A()
b.add_count()
print(b.count)
输出结果
1
2
从运行结果可以看出,虽然a和b是两个不同的A类的实例对象,但采用了__class__之后,分别调用两个对象add_count方法之后,获取到的对象count属性确是在不断累加的。此时self.__class__.count不再是单纯的某个对象私有属性,而是类的所有实例对象的共有属性,它相当于self.A.count。若将self.__class.count += 1变为self.count += 1,此时__class__的效果就十分明显了。
class A:
count =