Python交互设计_封装与泛化
一,封装
写一个函数叫做square,有一个名叫t的参数,这个t是一个 turtle。用这个turtle来画一个正方形。写一个函数调用,把bob作为参数传递给square,然后再运行这个程序。
$ cat mypolygon.py
#!/bin/python
import turtle
bob = turtle.Turtle()
def square(t):
for i in range(4):
t.fd(100)
t.lt(90)
square(bob)
在最内部的语句里面,fd和lt缩进了两次,这个意思是他们是for循环的循环体内部成员,而for循环本身缩进了一次,说明for语句被包含在函数的定义当中。
接下来的这行square(bob),紧靠左侧,没有缩进,这说明for循环和函数定义都结束了。
在函数体内部,t所指代的就是小乌龟bob,因此让t来左转九十度的效果,完全等同于让bob来左转九十度。这里没有把square函数的形式参数名字设置成bob,这是为啥呢?
是因为用t可以指代任意一个小乌龟,不仅仅是bob,所以你就能再创建另一个小乌龟,比如定义jack,把它传递给square这个函数作为实际参数:
$ cat mypolygon.py
#!/bin/python
import turtle
bob = turtle.Turtle()
def square(t):
for i in range(4):
t.fd(100)
t.lt(90)
square(bob)
jack = turtle.Turtle()
square(jack)
执行程序后,箭头会按照轨迹跑两次。第一次是调用bob,第二次是调用jack.
用函数的形式把一段代码包装起来,叫做封装,比如这里的square函数。
这样有一个好处,就是给代码起了个名字, 类似文档说明的功能(square意指四边形,而函数体就是画一个四边形)。另外一个好处是下次重复使用这段代码的时候,再次调用函数就可以了,这比复制粘贴函数体可方便多了。比如后面的square(jack),直接调用函数square,而不用拷贝一堆代码。
二,泛化
给square函数添加一个长度参数length:
#!/bin/python
import turtle
bob = turtle.Turtle()
def square(t,length): #添加length
for i in range(4):
t.fd(length) #替换为length
t.lt(90)
square(bob,100)
给函数添加参数,就叫做泛化,因为这可以让函数的功能更广泛。在这之前,square 函数画出来的四边形总是一个尺寸的,使用泛化后,就可以自定义边长了。
比如这里的square(bob,100) 可以写100,也可以写150,或者200等等其它数值。
再看一个例子,定义一个函数polygon,画多边形:
$ cat mypolygon.py
#!/bin/python
import turtle
bob = turtle.Turtle()
def polygon(t,n,length):
angle= 360 / n
for i in range(n):
t.fd(length)
t.lt(angle)
polygon(bob,7,70)
这个例子画了一个每个边长度都为70像素的七边形。
当一个函数有超过一个数据参数的时候,很容易忘掉这些参数都是什么,或者忘掉他们的顺序。为了避免这个情况,可以把形式参数的名字包含在一个实际参数列表中:
比如把n和length放到函数polygon的实际参数列表中:polygon(bob,n=7,length=70)
这些列表叫做关键参数列表,因为他们把形式参数的名字作为关键词包含了进来。(注意区别这里的关键词,不是Python语言的关键词。这里就是字面意思,很关键的词。)
这种语法结构让程序更容易被人读懂,也能提醒实际参数和形式参数的使用过程:调用一个函数的时候,把实际参数的值赋给了形式参数。
三,开发计划
开发计划是写程序的一系列过程。我们本章所用的就是『封装-泛化』的模式。这一过程的步骤如下:
1、开始写一个特别小的程序,没有函数定义。
2、一旦有你的程序能用了,确定一下实现功能的这部分有练习的语句,封装成函数,并命名。
3、通过逐步给这个函数增加参数的方式来泛化。
4、重复1-3步骤,一直到你有了一系列能工作的函数为止。把函数复制粘贴出来,避免重复输入或者修改了。
5、看看是不是有通过重构来改进函数的可能。比如,假设你在一些地方看到了相似的代码,就可以把这部分代码做成一个函数。
这个模式有一些缺点,我们后续会看到一些替代的方式,但这个模式是很有用的,尤其对那些实现不知道怎么去把程序分成多个函数的情况。
结束。