最近学习python的高阶教程的时候,发现python中__init__ 和 __new__ 比较难以理解,所以在网上又找了很多资料,因为都比较分散,所以将他们整合到这里,并添加一些自己的理解和代码运行试验。
参考文章来源
python 类中__new__ 和 __init__方法区别
Python面试之理解__new__和__init__的区别
分析
先说一些结论然后分析这两个函数在python的代码中是如何进行解释的
1)、__new__是一个静态方法,而__init__是一个实例方法
2)、__new__方法会返回一个创建的实例,而__init__什么都不返回
3)、只有在__new__返回一个cls的实例时,后面的__init__才能被调用
4)、当创建一个新实例时调用__new__,初始化一个实例时用__init__
5)、__init__ 方法为初始化方法, __new__方法才是真正的构造函数。
从上面罗列出来的结论上来看,__new__和__init__的区别在于,__new__是提供实例,而__init__则提供实例的初始化,因此如何理解实例与初始化的关系就是其区别的关键,我们来看一段代码。平常我们在学习的过程中会接触到的函数一般是__init__函数,而很少会写__new__,一个普通的Man类的实现如下
class Man:
def __init__(self):
print('__init__.A man.')
a=Man()
代码输出结果为:
__init__.A man.
调用Man类后,类会自动执行__init__函数,实现实例的初始化,看起来和__new__没有关系,但是实际上python 3.x中任何一个类都会继承一个object的基类,并继承基类的__new__方法。因此我们重构上面的Man类的__new__函数。
class Man(object):
def __new__(cls, *args, **kwargs):
instance=object.__new__(cls,*args, **kwargs)
print('__new__.A man.')
return instance
def __init__(self):
print('__init__.A man.')
a=Man()
代码输出
__new__.A man.
__init__.A man.
可以看到在调用__init__进行函数的初始化之前,类先调用了__new__方法,并且返回了一个instance对象,之后调用了函数的__init__方法。注意对于__new__函数而言,其必须有放回值,且这个返回值为类的实例,否则无法进行实例的初始化。而__init__则不允许有返回值。
TypeError: __init__() should return None, not 'int'
__new__的一些重要的功能
singleTon模式
这个模式指的的单例模式,及对于某一个类而言,这个类只会创建唯一的一个实例,其实现如下代码:
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
s1 = Singleton()
s2 = Singleton()
print(s1)
print(s2)
代码输出为:
<__main__.Singleton object at 0x000002201763BF28>
<__main__.Singleton object at 0x000002201763BF28>
如上的代码我们可以看到,虽然代码初始化了类的两个实例,但是由输出信息可以看到,两个实例存储在相同的位置,实际上为统一实例。容易看出__new__是为类提供实例的函数。
工厂模式
工厂模式指的是类可以根据输入信息实现自定义类转换的方式,对于python而言可以这样操作
class Fruit(object):
def __init__(self,k):
pass
def print_color(self):
pass
class Apple(Fruit):
def __init__(self):
print('this is an apple')
pass
def print_color(self):
print("apple is in red")
class Orange(Fruit):
def __init__(self):
print('this is an orange')
pass
def print_color(self):
print("orange is in orange")
class FruitFactory(object):
fruits = {"apple": Apple, "orange": Orange}
def __new__(cls, name):
if name in cls.fruits.keys():
return cls.fruits[name]()
else:
return Fruit()
def __init__(self):
print('this is fruitfactory')
fruit1 = FruitFactory("apple")
fruit2 = FruitFactory("orange")
fruit1.print_color()
fruit2.print_color()
代码输出:
this is an apple
this is an orange
apple is in red
orange is in orange
工厂模式中__new__接收参数,并返回相应的类的实例,并执行相应的初始化,而不执行自身的初始化函数。
metaclass元类
metaclass可以通过__new__函数实现对类的定制
#这个类的作用是将类的所有属性和方法前面都加上一个my_
class PrefixMetaclass(type):
def __new__(cls, name, bases, attrs):
# 给所有属性和方法前面加上前缀 my_
_attrs = (('my_' + name, value) for name, value in attrs.items())
_attrs = dict((name, value) for name, value in _attrs) # 转化为字典
_attrs['echo'] = lambda self, phrase: phrase # 增加了一个 echo 方法
return type.__new__(cls, name, bases, _attrs) # 返回创建后的类
class Foo(metaclass=PrefixMetaclass):
name = 'foo'
def bar(self):
print 'bar'
测试输出
f = Foo()
>>> f.name # name 属性已经被改变
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-774-4511c8475833> in <module>()
----> 1 f.name
AttributeError: 'Foo' object has no attribute 'name'
>>>
>>> f.my_name
'foo'
>>> f.my_bar()
bar
>>> f.echo('hello')
'hello'
可以看到所有的方法以及属性都被元类的__new__函数修改了。