【python】详解类class类的构造函数__new__和初始化函数__init__及定。。
⾸先回顾之前类的所有篇章:
【python】python中的类,对象,⽅法,属性初认识(⼀)
【python】详解类class的属性:类数据属性、实例数据属性、特殊的类属性、属性隐藏(⼆)
【python】详解类class的⽅法:实例⽅法、类⽅法、静态⽅法(三)
【python】详解类class的访问控制:单下划线与双下划线_(四)
【python】详解类class的继承、_ _ init_ _初始化、super⽅法(五)
【python】详解类class的⽅法解析顺序MRO(Method Resolution Order)(六)
【python】详解类class的通过_ _slots_ _限制类实例对象的属性(七)
从基本认识类,到深⼊认知类的属性、⽅法、访问控制、继承、限制等,最终完成⼀篇类的完整构造,如何去构建⼀个类。
1、类构造和初始化
我们定义⼀个类,并⽣成初始化_ _ init _ _ 对象函数和 _ _ new _ _对象函数:
class A(object):
def__init__(self,*args, **kwargs):
print"init %s" %self.__class__
def__new__(cls,*args, **kwargs):
print"new %s" %cls
return object.__new__(cls, *args, **kwargs)
a = A()
输出结果:
new <class'__main__.A'>
init <class'__main__.A'>
从结果可以看出,当实例化A类时,”_ _new _ _ “⽅法⾸先被调⽤,然后是” _ _ init _ _”⽅法。
⼀般来说,”_ _ init _ _ “和” _ _ new_ _”函数都会有下⾯的形式:
def__init__(self, *args, **kwargs):
# func_suite
def__new__(cls, *args, **kwargs):
# func_suite
return obj
对于”_ _new _ _ “和” _ _ init _ _”可以概括为:
“_ _new _ _ “⽅法在Python中是真正的构造⽅法(创建并返回实例),通过这个⽅法可以产⽣⼀个”cls”对应的实例对象,所以说” _ _ new _ _”⽅法⼀定要有返回
对于”_ _ init _ _ “⽅法,是⼀个初始化的⽅法,“self”代表由类产⽣出来的实例对象,” _ _ init _ _”将对这个对象进⾏相应的初始化操作
前⾯⽂章中已经介绍过了”_ _ init _ _ “的⼀些⾏为,包括继承情况中” _ _ init _ _ “的表现。下⾯就重点看看”_ _ new _ _”⽅法。
2、_ _ new_ _特性
“_ _ new_ _”是在新式类中新出现的⽅法,它有以下⾏为特性:
“_ _ new_ _” ⽅法是在类实例化对象时第⼀个调⽤的⽅法,将返回实例对象
“_ _ new_ _” ⽅法始终都是类⽅法(即第⼀个参数为cls),即使没有被加上装饰器
第⼀个参数cls是当前正在实例化的类,如果要得到当前类的实例,应当在当前类中的 “_ _ new _ _ ” ⽅法语句中调⽤当前类的⽗类的” _ _ new_ _” ⽅法
对于上⾯的第三点,如果当前类是直接继承⾃ object,那当前类的 “_new_” ⽅法返回的对象应该为:
def__new__(cls, *args, **kwargs):
# func_suite
return object.__new__(cls, *args, **kwargs)
2.1、重写_ _ new_ _
如果(新式)类中没有重写”_ _ new _ _ “⽅法,Python默认是调⽤该类的直接⽗类的” _ _ new_ _ “⽅法来构造该类的实例,如果该类的⽗类也没有重写” _ _ new _ _ “,那么将⼀直按照同样的规则追溯⾄object的”_ _new_ _”⽅法,因为object是所有新式类的基类。
⽽如果新式类中重写了”_ _new_ _ “⽅法,那么可以选择任意⼀个其他的新式类(必须是新式类,只有新式类有”_ _ new_ _ “,因为所有新式类都是从object派⽣)的”__ _ new _ _”⽅法来创建实例,包括这个新式类的所有前代类和后代类,只要它们不会造成递归死循环。
class Fun(object):
def__new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
# 这⾥的object.__new__(cls, *args, **kwargs) 等价于super(Fun, cls).__new__(cls, *args, **kwargs)
# object.__new__(Fun, *args, **kwargs)
# Ny.__new__(cls, *args, **kwargs)
# person.__new__(cls, *args, **kwargs),即使person跟Fun没有关系,也是允许的,因为person是从object派⽣的新式类
# 在任何新式类,不能调⽤⾃⾝的“__new__”来创建实例,因为这会造成死循环
# 所以要避免return Fun.__new__(cls, *args, **kwargs)或return cls.__new__(cls, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
class Ny(Fun):
def__new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
class person(object):
# person没有“__new__”⽅法,那么会⾃动调⽤其⽗类的“__new__”⽅法来创建实例,即会⾃动调⽤ object.__new__(cls)
pass
class girl(object):
def__new__(cls, *args, **kwargs):
# 可以选择⽤Bar来创建实例
obj = object.__new__(Ny, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
fun = Fun()
ny = Ny()
girl = girl()
输出结果:
Call __new__ for <class'__main__.Fun'>
Call __new__ for <class'__main__.Ny'>
Call __new__ for <class'__main__.Ny'>
2.2 、_ _ init_ _的调⽤
“_ _ new _ _ “决定是否要使⽤该类的” _ _ init_ _ “⽅法,因为”_ _ new _ _” 可以调⽤其他类的构造⽅法或者直接返回别的类创建的对象来作为本类的实例。
通常来说,新式类开始实例化时,”_ _ new _ _ “⽅法会返回cls(cls指代当前类)的实例,然后调⽤该类的”_ _ init_ _ “⽅法作为初始化⽅法,该⽅法接收这个实例(即self)作为⾃⼰的第⼀个参数,然后依次传⼊”_ _new _ _”⽅法中接收的位置参数和命名参数。
但是,如果”_ _ new _ _ “没有返回cls(即当前类)的实例,那么当前类的” _ _ init_ _”⽅法是不会被调⽤的。看下⾯的例⼦:
class A(object):
def__init__(self, *args, **kwargs):
print("Call __init__ from %s" %self.__class__)
def__new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
class B(object):
def__init__(self, *args, **kwargs):
print("Call __init__ from %s" %self.__class__)
def__new__(cls, *args, **kwargs):
obj = object.__new__(A, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
b = B()
print(type(b))
输出结果:
Call __new__ for <class'__main__.A'>
<class'__main__.A'>
2.3、派⽣不可变类型
关于”_ _ new_ _”⽅法还有⼀个重要的⽤途就是⽤来派⽣不可变类型。
例如,Python中float是不可变类型,如果想要从float中派⽣⼀个⼦类,就要实现”_ _ new _ _”⽅法:
class RoundTFloat(float):
def__new__(cls, num):
num = round(num, 4)
#return super(Round2Float, cls).__new__(cls, num)
return float.__new__(RoundTFloat, num)实例化类和实例化对象
num = RoundTFloat(3.141592654)
print(num)  #3.1416
3、定制⼀个类
在Python中,我们可以通过”魔术⽅法”使⾃定义的class变得强⼤、易⽤
调⽤魔术⽅法详细列表:
⽂中介绍了类的构造和初始化⽅法:”_ _ new _ _”和” _ _ init _ _ “。” _ _ new _ _ “⽅法是新式类特有的⽅法,通常情况下, _ _ new _ _ ⽅法会创建返回cls(cls指代当前类)的实例,然后调⽤该类的” _ _ init _ _ “⽅法作为初始化⽅法,该⽅法接收这个实例(即self)作为⾃⼰的第⼀个参数,然后依次传⼊” _ _ new _ _ “⽅法中接收的位置参数和命名参数;但是,如果” _ _ new _ _ “没有返回cls(即当前类)的实例,那么当前类的” _ _ init _ _”⽅法是不会被调⽤的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。