4.2.3 用函数增强程序的通用性

我们说过,程序 4.4 在减少重复代码和模块化两方面已经做得很好,但这并不意味着该 程序在各方面都已经完美。例如,如果我们希望换用字符"^"再画一棵树,以便比较哪个更 好看些,该如何做呢?显见的做法是仿照用"*"画树的代码重写画树冠的函数,而树干部分 可以重用。于是得到下面的代码:

【程序 4.5】tree5.py

def treetop1(): 
    print "   *" 
    print "  ***" 
    print " *****" 
    print "*******"
def treetop2(): 
    print "   ^" 
    print "  ^^^" 
    print " ^^^^^" 
    print "^^^^^^^"
def star_treetop(): 
    treetop1() 
    treetop1()
def caret_treetop(): 
    treetop2() 
    treetop2()
def treetrunk(): 
    print "   #"
    print "   #"
    print "   #"
def main():
    star_treetop() 
    treetrunk() 
    print 
    caret_treetop() 
    treetrunk()
main()

此版本的执行结果如下:

   *
  ***
 *****
*******
   *
  ***
 *****
*******
   #
   #
   #
   ^
  ^^^
 ^^^^^
^^^^^^^
   ^
  ^^^
 ^^^^^
^^^^^^^
   #
   #
   #

虽然程序 4.5 满足了功能需求,但是从程序设计角度说是很笨拙的,因为这是一种“头 痛医头脚痛医脚”的方法,即为每一种特殊情形创建新的代码。更好的做法是用一个一般的 函数来处理所有特殊情形。鉴于 treetop1 和 treetop2 的非常类似,我们可以从他们抽 象出一个通用的画树冠的函数,使得该函数能够取代 treetop1 和 treetop2。

函数的通用性可以通过引入参数(parameter)来实现。要理解参数的作用,可以简单地与数学函数的自变量进行类比。以函数 f(x) = x2 为例,对于给定的自变量值 10,函数计算 出函数值 f(10) = 100;换不同的自变量值 20,则函数又计算出另一个函数值 f(20) = 400。编 程语言中的函数参数具有类似的行为,输入不同的参数值,则函数执行后可产生不同的结果。

下面我们设计一个通用的画树冠的函数 treetop(ch),其中参数 ch 表示用来作画的 字符。为了控制树的形状,函数定义中使用了字符串格式化运算。

>>> def treetop(ch):
        print " %s" % (ch) 
        print " %s" % (3 * ch) 
        print " %s" % (5 * ch) 
        print "%s" % (7 * ch)

在交互环境定义了函数 treetop(ch)后,我们接着来测试它的效果。下面是测试例子:

>>> treetop('*')
   *
  ***
 *****
*******
>>> treetop('^')
   ^
  ^^^
 ^^^^^
^^^^^^^
>>> treetop('A') 
   A
  AAA 
 AAAAA 
AAAAAAA

可见函数 treetop(ch)确实具有通用性,只要为它的参数提供一个字符值,就能用该字符 画出树冠形状。下面我们利用 treetop(ch)函数来改写程序 4.5:

【程序 4.6】tree6.py

def treetop(ch):
    print " %s" % (ch) 
    print " %s" % (3 * ch) 
    print " %s" % (5 * ch) 
    print "%s" % (7 * ch)
def star_treetop(): 
    treetop("*")
    treetop("*")
def caret_treetop(): 
    treetop("^")
    treetop("^")
def treetrunk(): 
    print " #"
    print " #"
    print " #"
def main():
    star_treetop() 
    treetrunk() 
    print 
    caret_treetop() 
    treetrunk()
main()

此版本的执行结果和程序 4.5 完全一样,但是比较两者的代码会发现,程序 4.6 将程序 4.5

中的两个函数合二为一,增强了通用性。以后如果想换用其他字符画树,修改程序 4.6 比修

改程序 4.5 要简单得多。