《Python面向对象编程指南》——1.6 在每个子类中实现__init()__方法

1.6 在每个子类中实现__init()__方法

正如介绍工厂函数那样,这里我们也先看一些Card类的设计实例。我们可以考虑重构rank数值转换的代码,并把这个功能加在Card类上。这样就可以把初始化的工作分发到每个子类来完成。

这通常需要在基类中完成一些公共的初始化逻辑,子类中完成各自特殊的初始化逻辑。我们需要遵守不要重复自己(Don't Repeat Yourself,DRY)的原则来防止子类中的代码重复。

以下代码演示了如何把初始化职责分发到各自的子类中。

class Card:
  pass
class NumberCard( Card ):
  def __init__( self, rank, suit ):
    self.suit= suit
    self.rank= str(rank)
    self.hard = self.soft = rank
class AceCard( Card ):
  def __init__( self, rank, suit ):
    self.suit= suit
    self.rank= "A"
    self.hard, self.soft = 1, 11
class FaceCard( Card ):
  def __init__( self, rank, suit ):
    self.suit= suit
    self.rank= {11: 'J', 12: 'Q', 13: 'K' }[rank]
    self.hard = self.soft = 1

上例代码是多态的实现,由于缺乏公共初始化函数,导致了一些不受欢迎的重复代码。以上代码的主要重复部分是对suit的赋值。这部分代码放在基类中显然比较合适。我们可以在子类中显式调用基类的__init()__方法。

以下代码演示了如何把__init()__方法提到基类Card中实现的过程,然后在子类中可以重用基类的实现。

class Card:
  def __init__( self, rank, suit, hard, soft ):
    self.rank= rank
    self.suit= suit
    self.hard= hard
    self.soft= soft
class NumberCard( Card ):
  def __init__( self, rank, suit ):
    super().__init__( str(rank), suit, rank, rank )
class AceCard( Card ):
  def __init__( self, rank, suit ):
    super().__init__( "A", suit, 1, 11 )
class FaceCard( Card ):
  def __init__( self, rank, suit ):
    super().__init__( {11: 'J', 12: 'Q', 13: 'K' }[rank], suit,
10, 10 )

我们在子类和基类中都提供了__init()__方法的实现,这样会在一定程度上简化工厂函数的逻辑,如下面代码段所示。

def card10( rank, suit ):
  if rank == 1: return AceCard( rank, suit )
  elif 2 <= rank < 11: return NumberCard( rank, suit )
  elif 11 <= rank < 14: return FaceCard( rank, suit )
  else:
    raise Exception( "Rank out of range" )

仅仅是简化工厂函数不应该是我们重构焦点的全部。我们还应该看到这次的重构导致__init()__方法变得复杂了,做这样的权衡是正常的。

时间: 2024-07-30 15:02:56

《Python面向对象编程指南》——1.6 在每个子类中实现__init()__方法的相关文章

《Python面向对象编程指南》——1.5 通过工厂函数调用__init()__

1.5 通过工厂函数调用__init()__ 我们可以使用工厂函数来完成所有Card对象的创建,这比枚举52张牌的方式好很多.在Python中,实现工厂有两种途径. 定义一个函数,返回不同类的对象. 定义一个类,包含了创建对象的方法.这是完整的工厂设计模式,正如设计模式书中提到的.在类似Java这样的语言里,工厂类层次结构是必需的,因为语言本身不支持可以脱离类而单独存在的函数. 在Python里,类定义不是必需的.仅当特别复杂的情形,工厂类才是不错的选择.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.4 使用__init()__方法创建常量清单

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

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

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

《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面向对象编程指南》——2.9 new()方法和元类型

2.9 new()方法和元类型 __new__()方法的另一种用途,作为元类型的一部分,主要是为了控制如何创建一个类.这和之前的如何用__new__()控制一个不可变对象是完全不同的. 一个元类型创建一个类.一旦类对象被创建,我们就可以用这个类对象创建不同的实例.所有类的元类型都是type,type()函数被用来创建类对象. 另外,type()函数还可以被用作显示当前对象类型. 下面是一个很简单的例子,直接使用type()作为构造器创建了一个新的但是几乎完全没有任何用处的类: Useless=

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

1.2 基类中的__init__()方法 对象的生命周期主要包括了创建.初始化和销毁.后面章节会详细讨论对象的创建和销毁,本章专注于对象的初始化. object作为所有类的基类,已经为__init__()方法提供了默认实现,一般情况下不需要重写这个函数.如果没有对它进行重写,那么在创建对象时将不会产生其他变量的实例.在某些情况下,这种默认行为是可以接受的. 对于继承自object的子类,总可以对它的属性进行扩展.例如,对于下面这个类,实例化就不对函数(area)所需要的变量(width和leng