Python 类的 __new__ 和 __init__ 实现。
__ new__ 是Python类中最容易滥用的功能之一。 它晦涩难懂,到处都是陷阱,当您确实需要 __ new __ 时,它的功能就非常强大且难以理解。__ new __ 的主要用例在元类中。 元类非常复杂,相信深究Python元类编程的小伙,有本书值得你去读《Python Cookbook 第三版》但这本书要求读者最起码要有Python中级程度的基础,因为作者只给出大量用例,而甚少介绍Python解析器的执行原理,而元类编程的基础大量使用了魔术方法,其中充满陷进,比较难懂的就数__ new __。
class Fruint(object):
def __init__(self,name):
self.name=name
//构造
b=Fruit("banana")
在Python以及许多其他语言中,对象分为两个步骤:
- 生成对象要访问对象,必须先创建该对象。对象创建就需要为其分配对应类型尺寸的内存空间,该对象存在的唯一标识符就是其内存实体的内存地址,由于Python中的所有对象都继承基类object,因此创建对象会调用object.__ new__,而且__ new __会返回Fruit类的一个实例对象(通常指定为self)
self=obj.__new__(Fruit)
2 .构造对象:生成对象后,Python将该对象实例(,通常用self表示,对于C底层就是该Py结构体的指针)传递给该类的构造函数 __ init __,这一步通常是对类属性初始化或调用类内部的类方法,例如如下代码所示
Fruit.__init__(j,"banana")
注意,如果Fruit类重写了基类object的__ init __,情况会稍微复杂一些,例如Fruit类重写了这样函数签名
Fruit. __ new __(cls,name)
此时,不仅有Fruit. __ new __(cls,name)返回对象实例self,而且还有会将参数name传递给Fruit类的 __ init __构造函数,也就是说,就要求程序员必须显式定义Fruit. __ init __(self,name)这样的自定义构造函数和Fruit. __ new __(cls,name)相对应。
重写__ new__方法
因此我们知道 object .__ new__是对象实例化的默认步骤。 这就是从类创建实例的原因。 这是作为Fruit("banana")的第一部分隐式发生的。
注意,直到self通过__ init__运行之后才设置name属性。 因为object .__ new__不调用 __ init__。 它们是不同的方法。 如果我们想对对象实例self在构造函数运行之前对其进行操作,就是在类定义中显式重写__ new__。
Python允许我们通过__ new__ magic方法覆盖任何对象的__ new__。
class Fruit(object):
def __new__(cls,name):
obj=super(Fruit,cls).__new__(cls)
obj.name=name
__ new__将类而不是实例作为第一个参数。 由于它创建了一个实例,而使用 super(Fruit,cls). __ new__ (cls)是非常重要,而不能直接调用object .__ new__; 再次,原因后述。
下面的示例,展示了可以在显式重写的__ new__方法中,对定义类属性进行初始化,Python完全允许你这么做,但我们通常只在Python类的元编程才做这样的操作,类属性放在__ init__ 方法下更有意义
class Fruit(object):
def __new__(cls,name):
self=super(Fruit,cls).__new__(cls)
self.name=name
return self
def __repr__(self):
return self.name
我们对上面的Fruit类,按照常规的Python类实例化操作
b=Fruit("banana")
或者,我们显式执行Fruit.__ new__(Fruit,"banana"),输出的结果是一样的,但你会认为Python解释器在执行时,会一样吗?读者请自行思考一下。
上买的示例中,即便我们没有在Fruit类中显式定义__ init __方法,但当Python解析器在将Python源代码序列化为字节码的过程中,会隐含地为Fruit类添加默认的构造函数Fruit. __ init __(self,*args,**kwargs),即便这个默认构造是不做任何事
Python类的自定义构造函数
OK,我们通过下面几个反例子,没错,老子最喜欢用反面例子来说明问题的,我们Fruit类显式定义了__ init__构造函数,而且是一个默认构造,尝试运行的话出错,提示的传入参数的个数和显式定义了__ init__构造函数的个数冲突
到这里应该很好理解,我们上文已经说过了,我们只要在Fruit类显式定义Fruit类的自定义构造__ init __(self,name)或 __ init __(self,*args,**kwargs)就可以解决问题
或这样
小结
重要的事情说多一遍无妨,使用Python类的常规的实例化语句,例如:b=Fruit("banana"),Python实际上就分两步执行,详述见上文。
而显式执行Fruit. __ new __ (Fruit,"banana"),只会执行__ new __,而不会执行 __ init __
自定义的__ new __方法必须返回对象实例,而且对象通常有父类调用语句super(Fruit,cls). __ new __ (cls),请好好理解为什么要用关键字super,因为关键字super就是告知当前的子类Fruit“我的父类是object,别无他人”,再来个更复杂一点的
例如类Apple继承自类Fruit,当然类Fruit就继承自object,你会认为Apple.实例化时会跳过Fruit,直接调用object.__ new__(Apple)吗?一旦你这样做会令Apple-->Fruit-->object的任何继承信息(类属性和类方法)缺失(生动地说就是有歪轮常),因此super关键字是告知当前子类它指向子类“相对”的父类。
Ok,Python类的__ new__ ,__ init __和super关键字构成了Python类继承的基石,这些原理性的知识点你理解了,那么写这篇的目地是为Cython类继承做铺垫,这个目地就达成了。
推荐阅读
-
第一:C# 嵌入 Python 脚本进行图像处理并返回 C# 的构思和实现。
-
Python实现具备单一目标、多目标、多尺度和自定义特征的KCF跟踪算法实例代码
-
用Python实现2048小游戏(终端升级版)相比上篇 增添了撤回功能和历史最高分数的统计
-
Java 8新特性探究(十三)JavaFX 8新特性以及开发2048游戏-JavaFX历史## 跟java在服务器端和web端成绩相比,桌面一直是java的软肋,于是Sun公司在2008年推出JavaFX,弥补桌面软件的缺陷,请看下图JavaFX一路走过来的改进 从上图看出,一开始推出时候,开发者需使用一种名为JavaFX Script的静态的、声明式的编程语言来开发JavaFX应用程序。因为JavaFX Script将会被编译为Java bytecode,程序员可以使用Java代码代替。 JavaFX 2.0之后的版本摒弃了JavaFX Script语言,而作为一个Java API来使用。因此使用JavaFX平台实现的应用程序将直接通过标准Java代码来实现。 JavaFX 2.0 包含非常丰富的 UI 控件、图形和多媒体特性用于简化可视化应用的开发,WebView可直接在应用中嵌入网页;另外 2.0 版本允许使用 FXML 进行 UI 定义,这是一个脚本化基于 XML 的标识语言。 从JDK 7u6开始,JavaFx就与JDK捆绑在一起了,JavaFX团队称,下一个版本将是8.0,目前所有的工作都已经围绕8.0库进行。这是因为JavaFX将捆绑在Java 8中,因此该团队决定跳过几个版本号,迎头赶上Java 8。 ##JavaFx8的新特性 ## ###全新现代主题:Modena 新的Modena主题来替换原来的Caspian主题。不过在Application的start方法中,可以通过setUserAgentStylesheet(STYLESHEET_CASPIAN)来继续使用Caspian主题。 参考http://fxexperience.com/2013/03/modena-theme-update/ ###JavaFX 3D 在JavaFX8中提供了3D图像处理API,包括Shape3D (Box, Cylinder, MeshView, Sphere子类),SubScene, Material, PickResult, LightBase (AmbientLight 和PointLight子类),SceneAntialiasing等。Camera类也得到了更新。从JavaDoc中可以找到更多信息。 ###富文本 强化了富文本的支持 ###TreeTableView ###日期控件DatePicker 增加日期控件 ###用于 CSS 结构的公共 API
-
解析Python中的类的方法和概念
-
Python中的大顶堆和小顶堆:实现从小到大排序的大顶堆
-
使用Python快速实现图像的傅里叶变换和离散余弦变换
-
使用matplotlib在Python中实现正弦信号的时域波形和频谱图示例
-
用PyTorch和Python实现LSTM:时间序列预测的实战教程
-
Python 实现获取实时秒、分钟和小时的时间戳