python魔法函数
- 一. __new__
- 二. cls()函数
一. new
大家应该对__init__()方法都很熟悉,它的第一个参数一定是self,init()方法负责对象的初始化,系统执行该方法前,其实该实例对象已经存在,要不然初始化什么呢.通常来说,类开始实例化时,new()方法会返回cls(cls指代当前类)的实例,然后该类的__init__()方法会接收这个示例(即self)作为自己的第一个参数,然后依次转入__new__()方法中接收的位置参数和命名参数。
class Dog():def __new__(cls, *args, **kwargs):print("run the new of dog")#return super(Dog,cls).__new__(cls)return object.__new__(cls) #两条return语句作用相同def __init__(self):print("run the init of dog")print(self)print(self.__class__)a = Dog()# run the new of dog
# run the init of dog
# <__main__.Dog object at 0x00000197AAA3A8D0>
# <class '__main__.Dog'>可以看出,1.当我实例化Dog类对象时,python中首先调用的是类对象的__new__()方法,如果该对象没有定义__new__()方法,则去父类中依次查找,直到object类(object类是所有类的基类哦)。
2. __new__()的返回语句中,object.__new__(cls)意思是调用父类(object)的__new__(),super()是一个特殊函数,帮助python将父类和子类关联起来,父类也成超类,名称super因此得名。3. __new__()需要传递一个参数cls,__init__()需要传递一个参数self,self代表的就是实例对象本身,cls代表的是类对象本身。python中的self相当于C++的this指针。__new__()必须要有返回值,返回实例化出来的实例对象。
4.一般我们不会去重写__new__()方法,除非你确切知道怎么做,
什么时候你会去关心它呢,
它作为构造函数用于创建对象,是一个工厂函数,
专用于生产实例对象。著名的设计模式之一,
单例模式,就可以通过此方法来实现。
如果__new__()没有返回cls(即当前类的实例),那么当前类的__init__()方法是不会被调用的,如果__new__()返回了其他类的实例,那么只会调用被返回的那个类的构造方法。
class A(object):def __init__(self, *args, **kwargs):print("run the init of A")def __new__(cls, *args, **kwargs):print("run thr new of A")return object.__new__(B, *args, **kwargs)class B(object):def __init__(self):print("run the init of B")def __new__(cls, *args, **kwargs):print("run the new of B")return object.__new__(cls)a = A()
print(type(a))
# run thr new of A
# <class '__main__.B'>
b = B()
print(type(b))
# run the new of B
# run the init of B
# <class '__main__.B'>
其实__new__ 中的cls就是类本身,不是实例哦是类本身,下面看一个单例的实现:
# 实例化一个单例
class Singleton(object):__instance = Nonedef __new__(cls, age, name):#如果类数字__instance没有或者没有赋值#那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时#能够知道之前已经创建过对象了,这样就保证了只有1个对象if not cls.__instance:cls.__instance = object.__new__(cls)return cls.__instancedef __init__(self,age,name):self.age = ageself.name = name
a = Singleton(18, "wk")
b = Singleton(8, "mm")print(id(a)==id(b))
print(a.age,a.name)
print(b.age,b.name)
a.size = 19 #给a指向的对象添加一个属性
print(b.size)#获取b指向的对象的age属性# True
# 8 mm
# 8 mm
# 19对上面的代码优化下,只执行一次__init__:
# 实例化一个单例
class Singleton(object):__instance = None__first_init = Falsedef __new__(cls, age, name):if not cls.__instance:cls.__instance = object.__new__(cls)return cls.__instancedef __init__(self,age,name):if not self.__first_init:self.age = ageself.name = nameSingleton.__first_init = Truea = Singleton(18, "wk")
b = Singleton(8, "mm")print(id(a)==id(b))
print(a.age,a.name)
print(b.age,b.name)
a.size = 19 #给a指向的对象添加一个属性
print(b.size)#获取b指向的对象的age属性# True
# 18 wk
# 18 wk
# 19
- init()通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性,做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
- new()通常用于控制生成一个新实例的过程。它是类级别的方法。
- new()至少有一个参数cls,代表要实例化的类,此参数在实例化时会有python编辑器自动提供。
- new()必须有返回值,返回实例化出来的实例。
- 如果将类比作制造商,new()方法发就是前期的原材料环节,init()方法就是在有了原材料的基础上,加工,初始化商品的环节。
二. cls()函数
class Demo(object):def __init__(self,name,age):self.name=nameself.age=ageprint('__init__() called...')def __new__(cls, name, age):""":type name: str"""print('__new__() - {cls}'.format(cls=cls))return object.__new__(cls)@classmethoddef bu(cls,name,age):return cls(name,age)if __name__ == '__main__':# de = Demo(age=0,name="999")# print(de.name)# print(de.age)s = Demo.bu(name="张三", age=180)print(s.name)
cls(name, age) 实现了对 Demo 类的实例化,而 cls(name, age) 背后首先会调用 new 方法来创建对象,然后调用 init 方法来初始化对象