在编写类时经常会用到的三个函数__init__,__new__,super()。下面就简要阐述下这三个函数的用法。
1:__init__
__init__的方法一般都是用在初始化一个类的实例时候。如下
# -*- coding: utf-8 -*-
class Person(object):
"""Silly Person"""
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return '<Person: %s(%s)>' % (self.name, self.age)
if __name__ == '__main__':
piglei = Person('piglei', 24)
print piglei
__init__在初始化person实例的时候,需要传入两个值:name,age。并对实例self中的name,age进行赋值。(self表示实例化的对象)
2:__new__
__new__接受参数的形式和__init__时一样的,但是__new__是作用在创建实例的时候,__init__是创建完实例以后,对实例进行数据初始化的时候起作用的。
# -*- coding: utf-8 -*-
class Person(object):
"""Silly Person"""
def __new__(cls, name, age):
print '__new__ called.'
return super(Person, cls).__new__(cls, name, age)
def __init__(self, name, age):
print '__init__ called.'
self.name = name
self.age = age
def __str__(self):
return '<Person: %s(%s)>' % (self.name, self.age)
if __name__ == '__main__':
piglei = Person('piglei', 24)
print piglei
执行结果是
piglei@macbook-pro:blog$ python new_and_init.py
__new__ called.
__init__ called.
<Person: piglei(24)>
__new__先被执行,__init__后被执行。__new__会返回这个类的实例,它控制了一个类的实例化过程。super()
在类的继承中,使用该函数可以直接调用父类中的方法,而不用担心方法会被覆盖。如下
class Animal(object):
def __init__(self, name):
self.name = name
def greet(self):
print 'Hello, I am %s.' % self.name
class Dog(Animal):
def greet(self):
super(Dog, self).greet() # Python3 可使用 super().greet()
print 'WangWang...'
Animal是Dog的父类,在Dog的方法同名方法greet中可以直接通过super来调用父类中的方法。其中super比较常见的用法是在__init__初始化时使用。
class Base(object):
def __init__(self, a, b):
self.a = a
self.b = b
class A(Base):
def __init__(self, a, b, c):
super(A, self).__init__(a, b) # Python3 可使用 super().__init__(a, b)
self.c = c
深入super()
其实super和父类没有实质性的联系,是通过MRO(Method Resolution on Order)列表来进行关联的,MRO表示了类继承的顺序。
class Base(object):
def __init__(self):
print "enter Base"
print "leave Base"
class A(Base):
def __init__(self):
print "enter A"
super(A, self).__init__()
print "leave A"
class B(Base):
def __init__(self):
print "enter B"
super(B, self).__init__()
print "leave B"
class C(A, B):
def __init__(self):
print "enter C"
super(C, self).__init__()
print "leave C"
其中类C继承了A,B两个类,A,B都继承了Base类。
Base
/ \
/ \
A B
\ /
\ /
C
实例化结果
>>> c = C()
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
为什么在enter A后不是enter Base,而是enter B。下面我们通过MRO函数来看下类C的继承关系。
>>> C.mro() # or C.__mro__ or C().__class__.mro()
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
MRO函数显示出的继承关系,就是类C的实际继承效果。
super的工作原理如下
def super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
其中cls代表类,inst代表实例。
上面的代码做了两件事,获得实例inst的类的MRO列表,return返回MRO列表中的当前类的下一个类。所以是MRO控制了类和父类之间的跳转,而不是super调用了父类。