初始化__init__
init()方法意义重大的原因有两个。第一个原因是在对象生命周期中初始化是最重要的一步;每个对象必须正确初始化后才能正常工作。第二个原因是__init__()参数值可以有多种形式。
因为有很多种方式为__init__()提供参数值,对于对象创建有大量的用例,我们可以看看其中的几个。我们想尽可能的弄清楚,因此我们需要定义一个初始化来正确的描述问题区域。
在我们接触__init__()方法之前,无论如何,我们都需要粗略、简单地看看在Python中隐含的object类的层次结构。
超类object
每一个Python类都隐含了一个超类:object。它是一个非常简单的类定义,几乎不做任何事情。
示例1:
class X:
pass
>>> X.__class__
<class 'type'>
>>> X.__class__.__base__
<class 'object'>
该X类是type类的一个对象,且它的基类为object。
示例2:
class Rectangle:
def area(self):
return self.length * self.width
该类有一个使用两个属性来返回一个值的方法。这些属性没有初始化,却是合法的Python代码。它可以有效的避免专门设置属性,虽然感觉有点奇怪,但是有效。
>>> r = Rectangle()
>>> r.length, r.width = 13, 8
>>> r.area()
104
有时候我们不用在__init__()方法中设置所有属性,但 “显式比隐式更好。”
一个__init__()方法应该让实例变量显式。
可怜的多态
灵活和愚蠢就在一念之间。
当我们觉得需要像下面这样写的时候,我们正从灵活的边缘走向愚蠢:
if 'x' in self.__dict__:
或
try:
self.x
except AttributeError:
是时候重新考虑API并添加一个通用的方法或属性。重构比 添加if语句 更明智。
在超类中实现init()
调用超类__init__()方法,通用初始化可以适用于多个子类。
此函数通常用来创建对象的实例变量,并执行任何其他一次性处理。
class Card:
def __init__(self, rank, suit):
self.suit = suit
self.rank = rank
self.hard, self.soft = self._points()
class NumberCard(Card):
def _points(self):
return int(self.rank), int(self.rank)
class AceCard(Card):
def _points(self):
return 1, 11
class FaceCard(Card):
def _points(self):
return 10, 10
这是一种常见的多态设计。每一个子类都提供一个唯一的_points()方法实现。
创建__new__
__new__方法在类定义中不是必须写的,如果没定义,默认会调用object.__new__去创建一个对象。如果定义了,就是override,可以自定义custom创建对象的行为。
class Bar(object):
pass
class Foo(object):
def __new__(cls, *args, **kwargs):
return Bar()
print Foo()
在这里做一下手脚,每次创建对象都返回同一个,那不就是单例模式了吗?没错,就是这样。可以观摩《飘逸的python - 单例模式乱弹》
定义单例模式时,因为自定义的__new__重载了父类的__new__,所以要自己显式调用父类的__new__,即object.new(cls, *args, **kwargs),或者用super()。,不然就不是extend原来的实例了,而是替换原来的实例。
对于__call__
对象通过提供__call__(slef, [,*args [,**kwargs]])方法可以模拟函数的行为,如果一个对象x提供了该方法,就可以像函数一样使用它,也就是说x(arg1, arg2…) 等同于调用x.call(self, arg1, arg2) 。模拟函数的对象可以用于创建防函数(functor) 或代理(proxy).
总结
在Python中,类的行为就是这样,new、init、__call__等方法不是必须写的,会默认调用,如果自己定义了,就是override,可以custom。既然override了,通常也会显式调用进行补偿以达到extend的目的。
这也是为什么会出现"明明定义"了:
def _init__(self, *args, **kwargs)
对象怎么不进行初始化"这种看起来诡异的行为。
(注,这里_init__少写了个下划线,因为__init__不是必须写的,所以这里不会报错,而是当做一个新的方法_init__)
————————————————
感谢:
https://blog.csdn.net/weixin_45707610/article/details/131637978
https://blog.csdn.net/qq_15821487/article/details/119737869