python 详解类class类的构造函数__new__和初始化函数__init__(八)

从基本认识类,到深入认知类的属性、方法、访问控制、继承、限制等,如何去构建一个类。

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 _ _ “方法会返回clscls指代当前类的实例,然后调用该类的”_ _ 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(RoundTFloat, cls).__new__(cls, num)
#         return float.__new__(cls, num)

num = RoundTFloat(3.141592654)
print(num)   #3.1416
print(num.__class__)
3.1416
<class '__main__.RoundTFloat'>

 

 

3、定制一个类

  • 在Python中,我们可以通过”魔术方法”使自定义的class变得强大、易用

文中介绍了类的构造和初始化方法:”_ _ new _ _”和” _ _ init _ _ “。” _ _ new _ _ “方法是新式类的方法,通常情况下, _ _ new _ _ 方法会创建返回cls(cls指代当前类)的实例,然后调用该类的” _ _ init _ _ “方法作为初始化方法,该方法接收这个实例(即self)作为自己的第一个参数,然后依次传入” _ _ new _ _ “方法中接收的位置参数和命名参数;但是,如果” _ _ new _ _ 没有返回cls(即当前类)的实例,那么当前类的” _ _ init _ _”方法是不会被调用的。

 

 

 

 

 

 

 

  • 7
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python中,可以在的方法中调用`__init__`函数。`__init__`函数是一个特殊的方法,用于在创建对象时进行初始化操作。通常情况下,`__init__`函数会在对象创建后自动调用,不需要手动调用。但是,在的其他方法中,如果需要重新初始化对象的某些属性,可以通过调用`__init__`函数来实现。 例如,假设有一个`MyClass`,其中定义了`__init__`函数和另一个方法`my_method`,可以在`my_method`方法中调用`__init__`函数来重新初始化对象的属性。代码示例如下: ```python class MyClass: def __init__(self, value): self.value = value def my_method(self, new_value): self.__init__(new_value) obj = MyClass(10) print(obj.value) # 输出: 10 obj.my_method(20) print(obj.value) # 输出: 20 ``` 在上述代码中,首先创建了一个`MyClass`的对象`obj`,并将属性`value`初始化为10。然后,在`my_method`方法中调用了`__init__`函数,并传入新的值20,从而重新初始化了`obj`的`value`属性。最后,打印`obj.value`的值,可以看到属性值已经被更新为20。 需要注意的是,调用`__init__`函数会重新初始化对象的所有属性,因此在调用时需要谨慎处理。另外,如果在`__init__`函数中有一些其他的初始化操作,也需要考虑是否需要在其他方法中再次执行这些操作。 #### 引用[.reference_title] - *1* [python - 在__init__中调用函数](https://blog.csdn.net/weixin_39818727/article/details/110046934)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Python中 self函数和_init_函数的用法以及成员函数的调用](https://blog.csdn.net/weixin_62393334/article/details/126754697)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Python构造函数__init__(self)和析构函数__del__详解](https://blog.csdn.net/weixin_39636645/article/details/110163480)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_yuki_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值