Fork me on GitHub

Python中的常用的__方法

__new__、__init__、__call__的介绍

  在讲到使用元类创建单例模式之前,比需了解__new__这个内置方法的作用,在上面讲元类的时候我们用到了__new__方法来实现类的创建。然而我在那之前还是对__new__这个方法和__init__方法有一定的疑惑。因此这里花点时间对其概念做一次了解和区分。

__new__ 创建新对象

  __new__方法负责创建一个实例对象,在对象被创建的时候调用该方法它是一个类方法。__new__方法在返回一个实例之后,会自动的调用__init__方法,对实例进行初始化。如果__new__方法不返回值,或者返回的不是实例,那么它就不会自动的去调用__init__方法。

__init__ 实例化

  __init__ 方法负责将该实例对象进行初始化,在对象被创建之后调用该方法,在__new__方法创建出一个实例后对实例属性进行初始化。__init__方法可以没有返回值。

__call__ 调用

  __call__方法其实和类的创建过程和实例化没有多大关系了,定义了__call__方法才能被使用函数的方式执行。

例如:
class A(object):
    def __call__(self):
        print "__call__ be called"

a = A()
a()
#输出
#__call__ be called

打个比方帮助理解:如果将创建实例的过程比作建一个房子。

  • 那么class就是一个房屋的设计图,他规定了这个房子有几个房间,每个人房间的大小朝向等。这个设计图就是累的结构
  • __new__就是一个房屋的框架,每个具体的房屋都需要先搭好框架后才能进行专修,当然现有了房屋设计才能有具体的房屋框架出来。这个就是从类到类实例的创建。
  • __init__就是装修房子的过程,对房屋的墙面和地板等颜色材质的丰富就是它该做的事情,当然先有具体的房子框架出来才能进行装饰了。这个就是实例属性的初始化,它是在__new__出一个实例后才能初始化。
  • __call__就是房子的电话,有了固定电话,才能被打电话嘛(就是通过括号的方式像函数一样执行)。
#coding:utf-8
class Foo(object):
    def __new__(cls, *args, **kwargs):
        #__new__是一个类方法,在对象创建的时候调用
        print "excute __new__"
        return super(Foo,cls).__new__(cls,*args,**kwargs)


    def __init__(self,value):
        #__init__是一个实例方法,在对象创建后调用,对实例属性做初始化
        print "excute __init"
        self.value = value


f1 = Foo(1)
print f1.value
f2 = Foo(2)
print f2.value

#输出===:
excute __new__
excute __init
excute __new__
excute __init
#====可以看出new方法在init方法之前执行

子类如果重写__new__方法,一般依然要调用父类的__new__方法。

class Child(Foo):
    def __new__(cls, *args, **kwargs):        
        return suyper(Child, cls).__new__(cls, *args, **kwargs)

必须注意的是,类的__new__方法之后,必须生成本类的实例才能自动调用本类的__init__方法进行初始化,否则不会自动调用__init__.

class Foo(object):
    def __init__(self, *args, **kwargs):
        print "Foo __init__"
    def __new__(cls, *args, **kwargs):
        return object.__new__(Stranger, *args, **kwargs)

class Stranger(object):
    def __init__(self,name):
        print "class Stranger's __init__ be called"
        self.name = name

foo = Foo("test")
print type(foo) #<class '__main__.Stranger'>
print foo.name #AttributeError: 'Stranger' object has no attribute 'name'

#说明:如果new方法返回的不是本类的实例,那么本类(Foo)的init和生成的类(Stranger)的init都不会被调用

 

posted @ 2018-06-26 21:05  马一特  阅读(605)  评论(0)    收藏  举报