python类中 __new__ 和__init__的区别和联系

        最近学习python的高阶教程的时候,发现python中__init__ 和 __new__ 比较难以理解,所以在网上又找了很多资料,因为都比较分散,所以将他们整合到这里,并添加一些自己的理解和代码运行试验。

 

参考文章来源

python 类中__new__ 和 __init__方法区别

Python面试之理解__new__和__init__的区别

陌生的 metaclass

分析

先说一些结论然后分析这两个函数在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__函数修改了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章