《Python面向对象编程指南》——1.2 基类中的__init__()方法

1.2 基类中的__init__()方法

对象的生命周期主要包括了创建、初始化和销毁。后面章节会详细讨论对象的创建和销毁,本章专注于对象的初始化。

object作为所有类的基类,已经为__init__()方法提供了默认实现,一般情况下不需要重写这个函数。如果没有对它进行重写,那么在创建对象时将不会产生其他变量的实例。在某些情况下,这种默认行为是可以接受的。

对于继承自object的子类,总可以对它的属性进行扩展。例如,对于下面这个类,实例化就不对函数(area)所需要的变量(width和length)进行初始化。

class Rectangle:
  def area( self ):
    return self.length * self.width

Rectangle类的area函数在返回值时使用了两个属性,可并没有在任何地方对其赋值。在Python中,这种看似奇怪的调用尚未赋值属性的操作却是合法的。

下面这段代码演示如何使用刚定义的Rectangle类。

>>> r= Rectangle()
>>> r.length, r.width = 13, 8
>>>r.area()
104

虽然这种延迟赋值的实现方式在Python中是合法的,但是却给调用者带来了潜在的困惑,因此要尽量避免这样的用法。

然而,这样的设计看似又提供了灵活性,意味着在__init__()方法被调用时不必为所有的属性赋值。这看似是不错的选择,一个可选属性即可以看作是某子类中的成员,且无须对这个子类进行显式地定义就可以完成对原生机制的扩展。然而这种多态机制不但给程序带来了隐藏的不确定性,也会相应产生很多令人费解的if语句。

因此,延迟初始化属性的设计在某种情形下可能会有用,可是这样也可能会导致非常糟糕的设计。

在Zen of python poem一书中曾提出过这样的建议:

“显式而非隐式”。

对于每个__init__()方法,都应当显式地指定要初始化的变量。

时间: 2024-09-30 21:40:00

《Python面向对象编程指南》——1.2 基类中的__init__()方法的相关文章

《Python面向对象编程指南》——1.9 不带__init__()方法的无状态对象

1.9 不带__init__()方法的无状态对象 以下是一个不需要__init__()方法的类定义.对于策略模式的对象来说这是常见的设计.一个策略对象以插件的形式复合在主对象上来完成一种算法或逻辑.它或许依赖主对象中的数据,策略对象自身并不携带任何数据.通常策略类会和享元设计模式一起使用:在策略对象中避免内部存储.所有需要的值都从策略对象的方法参数传入.策略对象自身是无状态的,可以把它看作是一系列函数的集合. 这里定义了一个类给Player实例提供游戏模式的选择,以下这个策略包括了拿牌和下调投注

《Python面向对象编程指南》——1.12 更多的__init__()技术

1.12 更多的__init__()技术 我们再来看一下其他一些更高级的__init__()技术的应用.相比前面的介绍,它们的应用场景不是特别常见. 以下是Player类的定义,初始化使用了两个策略对象和一个table对象.这个__init__()函数看起来不够漂亮. class Player: def __init__( self, table, bet_strategy, game_strategy ): self.bet_strategy = bet_strategy self.game_

《Python面向对象编程指南》——1.4 使用__init()__方法创建常量清单

1.4 使用__init()__方法创建常量清单 我们可以为所有卡片的花色单独创建一个类.可在21点应用中,花色不是很重要,用一个字母来代替就可以. 这里使用花色的初始化作为创建常量对象的一个实例.很多情况下,应用会包括一个常量集合.静态常量也正构成了策略(Strategy)或状态(State)模式的一部分. 有些情况下,常量会在应用或配置文件的初始化阶段被创建.或者创建变量的行为是基于命令行参数的.我们会在第16章"使用命令行"中介绍应用初始化和启动的详细设计过程. Python中并

《Python面向对象编程指南》——导读

前 言 本书主要介绍Python语言的高级特性,特别是如何编写高质量的Python程序.这通常意味着编写高性能且拥有良好可维护性的程序.同时,我们也会探究不同的设计方案并确定究竟是哪种方案提供了最佳性能.而对于一些正在寻找解决方案的问题,这也是一种很好的方式. 本书的大部分内容将介绍一种给定设计的不同替代方案.一些方案性能更好,另一些方案更加简单或者更加适合于特定领域的问题.最重要的是,找到最好的算法和最优的数据结构,以最少的开销换取最大的价值.时间就是金钱,高效的程序会为它们的用户创造更多的价

《Python面向对象编程指南》——第1部分 用特殊方法实现Python风格的类 第1章 __init__()方法 1.1 隐式的基类——object

第1部分 用特殊方法实现Python风格的类 init()方法 与Python无缝集成--基本特殊方法 属性访问.特性和修饰符 抽象基类设计的一致性 可调用对象和上下文的使用 创建容器和集合 创建数值类型 装饰器和Mixins--横切方面 用特殊方法实现 Python风格的类 通过重写特殊方法来完成对Python内部机制的调用,在Python中是很普遍的.例如len()函数就可以重写一个类的__len__()方法. 这意味着对于像(len(x))这样的通用公共接口,任何类(例如,声明一个类叫ti

《Python面向对象编程指南》——1.3 在基类中实现init()方法

1.3 在基类中实现init()方法 通过实现__init()__方法来初始化一个对象.每当创建一个对象,Python会先创建一个空对象,然后调用该对象的__init()__函数.这个方法提供了对象内部变量以及其他一些一次性过程的初始化操作. 以下是关于一个Card类层次结构定义的一些例子.这里定义了一个基类和3个子类来描述Card类的基本信息.有两个变量是参数直接赋值的,另外两个参数是通过初始化方法计算来完成初始化的. class Card: def __init__( self, rank,

《Python面向对象编程指南》——1.10 一些其他的类定义

1.10 一些其他的类定义 正如前面所提到的,玩家有两种策略:下注和打牌.每个Player实例会和模拟器进行很多交互.我们这里把这个模拟器命名为Table类. Table类的职责需要配合Player实例完成以下事件. 玩家必须基于玩牌策略初始化一个牌局. 随后玩家会得到一手牌. 如果手中的牌是可以拆分的,玩家需要在基于当前玩法的情况下决定是否分牌.这会创建新的Hand对象.在一些场合中,新分出去的牌是可以再分的. 对于每个Hand实例,玩家必须基于当前玩法决定叫牌.双倍还是停叫. 然后玩家会收到

《Python面向对象编程指南》——1.7 简单的组合对象

1.7 简单的组合对象 一个组合对象也可以称作容器.我们会从一个简单的组合对象开始介绍:一副牌.这是一个基本的集合对象.我们的确可以简单地使用一个list来代替一副牌(deck)对象. 在设计一个类之前,我们需要考虑这样的一个问题:简单地使用list是合适的做法吗? 可以使用random.shuffle()函数完成洗牌操作,使用deck.pop()来完成发牌操作. 一些程序员可能会过早定义新类,正如像使用内置类一样,违反了一些面向对象的设计原则.比如像下面的这个设计. d= [card6(r+1

《Python面向对象编程指南》——2.4 __bool__()方法

2.4 __bool__()方法 Python中有很多关于真假性的定义.参考手册中列举了许多和False等价的值,包括False.0.''.().[]和{}.其他大部分的对象都和True等价. 通常,我们会用下面的语句来测试一个对象是否"非空". if some_object: process( some_object ) 默认情况下,这个是内置的bool()函数的逻辑.这个函数依赖于一个给定对象的__bool__()方法. 默认的__bool__()方法返回True.我们可以通过下面