《Python面向对象编程指南》——2.8 __new__()方法和不可变对象

简介:

本节书摘来自异步社区《Python面向对象编程指南》一书中的第2章,第2.8节,作者[美]Steven F. Lott, 张心韬 兰亮 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.8 __new__()方法和不可变对象

__new__方法的一个用途是初始化不可变对象。__new__()方法中允许创建未初始化的对象。这允许我们在__init__()方法被调用之前先设置对象的属性。

由于不可变类的__init__()方法很难重载,因此__new__方法提供了一种扩展这种类的方法。

下面是一个错误定义的类,我们定义了float的一个包含单位信息的版本。

class Float_Fail( float ):
   def __init__( self, value, unit ):
     super().__init__( value )
     self.unit = unit

我们试图(不合理地)初始化一个不可变对象。

下面是当我们试图使用这个类时会发生的情况。

>>> s2 = Float_Fail( 6.5, "knots" )
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: float() takes at most 1 argument (2 given)

可以看到,对于内置的float类,我们不能简单地重载__init__方法。对于其他的内置不可变类型,也有类似的问题。我们不能在不可变对象self上设置新的属性值,因为这是不可变性的定义。我们只能在对象创建的过程中设置属性值,对象创建之后__new__()方法就会被调用。

__new__()方法天生就是一个静态方法。即使没有使用@staticmethod修饰符,它也是静态的。它没有使用self变量,因为它的工作是创建最终会被赋值给self变量的对象。

这种情况下,我们会使用的方法签名是__new__( cls, args, *kw)。cls变量是准备创建的类的实例。下一个部分关于元类型的例子,会比这里展示的args的参数序列更加复杂。

__new__()方法的默认实现如下。

return super().__new__( cls )将调用基类的__new__()方法创建对象。这个工作最终委托给了object.__new__(),这个方法创建了一个简单的空对象。除了cls以外,其他的参数和关键字最终都会传递给__init__()方法,这是Python定义的标准行为。

除了有下面的两个例外,这就是我们期望的行为。

  • 当我们需要继承一个不可变的类的时候,我们会在后面的部分详细讲解。
  • 当我们需要创建一个元类型的时候,这是下一个部分的主题,因为它与创建不可变对象是完全不同的。

当创建一个内置的不可变类型的子类时,不能重载__init__()方法。取而代之的是,我们必须通过重载__new__()方法在对象创建的过程中扩展基类的行为。下例是扩展float类的正确方式。

class Float_Units( float ):
   def __new__( cls, value, unit ):
     obj= super().__new__( cls, value )
     obj.unit= unit
     return obj

上面的代码在对象创建的过程中设置了一个属性的值。

下面的代码使用上面定义的类创建了一个带单位的浮点数。

>>>speed= Float_Units( 6.5, "knots" )
>>>speed
6.5
>>>speed * 10
65.0
>>> speed.unit
'knots'

注意,像speed * 10这种表达式不会创建一个Float_Units对象。这个类的定义继承了float中所有的运算符;float的所有算术特殊方法也都只会创建float对象。创建Float_Units对象会在第7章“创建数值类型”中介绍。

相关文章
|
5月前
|
测试技术 开发者 Python
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
本文介绍Python单元测试基础,详解`unittest`框架中的三大核心断言方法:`assertEqual`验证值相等,`assertTrue`和`assertFalse`判断条件真假。通过实例演示其用法,帮助开发者自动化检测代码逻辑,提升测试效率与可靠性。
481 1
|
6月前
|
机器学习/深度学习 数据采集 数据挖掘
基于 GARCH -LSTM 模型的混合方法进行时间序列预测研究(Python代码实现)
基于 GARCH -LSTM 模型的混合方法进行时间序列预测研究(Python代码实现)
237 2
|
6月前
|
调度 Python
微电网两阶段鲁棒优化经济调度方法(Python代码实现)
微电网两阶段鲁棒优化经济调度方法(Python代码实现)
181 0
|
5月前
|
人工智能 数据安全/隐私保护 异构计算
桌面版exe安装和Python命令行安装2种方法详细讲解图片去水印AI源码私有化部署Lama-Cleaner安装使用方法-优雅草卓伊凡
桌面版exe安装和Python命令行安装2种方法详细讲解图片去水印AI源码私有化部署Lama-Cleaner安装使用方法-优雅草卓伊凡
785 8
桌面版exe安装和Python命令行安装2种方法详细讲解图片去水印AI源码私有化部署Lama-Cleaner安装使用方法-优雅草卓伊凡
|
6月前
|
机器学习/深度学习 数据采集 算法
【CNN-BiLSTM-attention】基于高斯混合模型聚类的风电场短期功率预测方法(Python&matlab代码实现)
【CNN-BiLSTM-attention】基于高斯混合模型聚类的风电场短期功率预测方法(Python&matlab代码实现)
375 4
|
5月前
|
算法 调度 决策智能
【两阶段鲁棒优化】利用列-约束生成方法求解两阶段鲁棒优化问题(Python代码实现)
【两阶段鲁棒优化】利用列-约束生成方法求解两阶段鲁棒优化问题(Python代码实现)
158 0
|
6月前
|
机器学习/深度学习 数据采集 TensorFlow
基于CNN-GRU-Attention混合神经网络的负荷预测方法(Python代码实现)
基于CNN-GRU-Attention混合神经网络的负荷预测方法(Python代码实现)
358 0
|
Python
Python中__new__和__init__的区别与联系
Python中__new__和__init__的区别与联系
288 0
|
Python
|
Python
【Python之理解__new__和__init__的区别】
【Python之理解__new__和__init__的区别】
221 0

推荐镜像

更多