Python面向对象编程基础:__init__()、__new__、__call__方法

初始化__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中,类的行为就是这样,newinit、__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

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值