You are on page 1of 177

计算机程序设计基础 Python

清华大学计算机科学与技术系 乔 林
第三章 函数与模块 Python
清华大学计算机科学与技术系 乔 林
3.1  函数调用
3.2  函数定义
3.3  名空间与作用域
3.4  函数参数
3.5  递 归
3.6  模 块

第三章 函数与模块 3
计算机程序设计基础( Python ) 4
3.1  函数调用
3.2  函数定义
3.3  名空间与作用域
3.4  函数参数
3.5  递 归
3.6  模 块

第三章 函数与模块 5
3.1  函数调用 6
3.1.1  函数基本概念
3.1.2  函数调用规范
3.1.3  内置函数
3.1.1  函数基本概念
• 函数 (function) :具有特定功能的可重用代码片段,
实现解决某个特定问题的算法( algorithm )
• 函数在需要时被调用,其代码被执行
• 函数一般具有唯一的名称以供调用
• 函数主要通过接口( interface )与外界通信,传递信息
• 目的与意义
• 程序功能抽象,以支持代码重用
• 使用时无需了解函数内部实现细节
• 有助于采用分而治之的策略编写大型复杂程序
7
3.1.2  函数调用规范
• 主调函数与被调函数
• 主调函数( caller ,客户函数):调用其他函数的函数
• 被调函数( callee ,服务器函数):被其他函数调用的函数
• 函数调用( function call/invocation )格式
• 格式: function_name([parameter_list])
• 无论参数是否存在,函数调用小括号均不能省略
• 参数传递:函数调用时通过 parameter_list 传递实际参数,
所传递的实际参数列表必须与函数定义时的形式参数列表匹配
• 函数返回值:若存在,可参与后续运算或赋给其他数据对象
8
3.1.2  函数调用规范
• 基本调用逻辑:函数只能调用已实现的函数
• 控制流程
• 函数调用时: Python 暂时中断主调函数的流程,转而执行被
调函数代码
• 函数调用后:被调函数执行完毕,控制流重新转回主调函数,
继续执行主调函数后续代码
• 函数通信:函数接口
• 主要技术手段:函数参数与返回值
• 其他:可共享访问的数据对象
9
函数调用示例:银河系漫游指南
• 函数调用示例:第〇章示例三
# Douglas Noël Adams: The Hitchhiker's Guide to the Galaxy
>>> The_Ultimate_Question = \
... "The Question of Life, the Universe and Everything"
# 获取字符串长度,扣除其中的七个空格,赋值给变量 Deep_Thought
>>> Deep_Thought = len(The_Ultimate_Question) – 7
# 打印 ASCII/Unicode 码值为该整数的字符
>>> print(chr(Deep_Thought))
*

10
3.1.3  内置函数
• 内置函数与 Python 版本有关
• 不同 Python 版本提供的内置函数的数目与性质可能不同
• Python 3.6 内置函数:总计 68 个
• 部分数值相关函数请参阅第 1.4.5 节与第 2.1.1 节: abs() 、
bin() 、 bool() 、 complex() 、 divmod() 、 float() 、 hex() 、 i
nt() 、 max() 、 min() 、 oct() 、 pow() 、 round()
• 部分输入输出相关函数请参阅第 1.6 节: eval() 、 input() 、
print() 、 raw_input()
• 区间函数请参阅第 2.3.2 节: range()

11
3.1.3  内置函数
• 函数 all(iterable) :若 iterable 的全部元素为 True ,返回
True ,否则返回 False
• 函数 any(iterable) :若 iterable 的某个元素为 True ,返回
True ,否则返回 False
• 函数 ascii(object) :与函数 repr() 类似,返回表示对象
object 的可打印字符串
• 函数 class bytearray([source[, encoding[, errors]]]) :返回一个
内容可变的字节整数数组对象
• 函数 class bytes([source[, encoding[, errors]]]) :返回一个内容
不变的字节整数序列对象
12
3.1.3  内置函数
• 函数 callable(object) :若 object 可调用,返回 True ,否则
返回 False
• 函数 chr(i) :返回整数 i 所表示 Unicode 字符对应的字符串
• 本函数为 ord() 函数的逆运算
• 整数 i 位于区间 [0, 1114111(0x10FFFF)]
• 函数 classmethod(function) :返回 functiuon 的类方法
• 函数 compile(source, filename, mode, flags = 0, dont_inherit =
False, optimize = -1) :将 source 编译为代码对象或抽象语法树
( AST )对象;代码对象可以由函数 exec() 或 eval() 执行,
source 可以为普通字符串、字节字符串或抽象语法树对象
13
3.1.3  内置函数
• 函数 delattr(object, name) :在对象 object 允许时删除其属性,
name 为该属性对应的字符串名称
• 函数 class dict(**kwarg) 、 class dict(mapping, **kwarg) 、
class dict(iterable, **kwarg) :创建一个新字典
• 函数 dir([object]) :无参数时返回当前局部作用域的名称列表;
有参数时试图返回该对象的有效属性列表
• 函数 enumerate(iterable, start = 0) :返回一个枚举对
象, iterable 必须是序列、迭代器或其他支持迭代的对象
• 函数 exec(object[, globals[, locals]]) :动态执行 Pyhton 代码,
object 必须是字符串或代码对象
14
3.1.3  内置函数
• 函数 filter(function, iterable) :过滤器,为 iterable 中
function 返回 True 的全部元素构造迭代器
• 函数 format(value[, format_spec]) :按照 format_spec 的规范,
将 value 转换为格式化的字符串
• 函数 class frozenset([iterable]) :返回一个 frozenset 对
象, frozenset 为元素内容不变的集合类型
• 函数 getattr(object, name[, default]]) :返回 object 的 name
属性值
• 函数 globals() :返回当前全局符号表字典

15
3.1.3  内置函数
• 函数 hasattr(object, name) :判断 object 是否具有 name 属
性,如有返回 True ,否则返回 False
• 函数 hash(object) :返回 object 的哈希值
• 函数 help([object]) :调用内置帮助系统
• 函数 id(object) :返回 object 的本征值,返回值为与 object
对应的全局唯一常整数
• 函数 isinstance(object, classinfo) :如果 object 为类型
classinfo 的对象,返回 True ,否则返回 False

16
3.1.3  内置函数
• 函数 issubclass(class, classinfo) :如果类型 class 为类型
classinfo 的子类,返回 True ,否则返回 False
• 函数 iter(object[, sentinel]) :返回 object 的迭代器
• 函数 len(s) :返回 s 的长度或项数
• 函数 class list([iterable]) :构造一个列表对象
• 函数 locals() :更新和返回当前局部符号表字典
• 函数 map(function, iterable, ...) :返回一个迭代器,将
function 作用到 iterable 的每个对象上

17
3.1.3  内置函数
• 函数 max(iterable, *[, default, key]) 、 max(arg1, arg2, *args,
*[, key]) :返回数据集中元素的最大者
• 此为细化版本
• 若传递单一位置参数,则必须为可迭代对象 iterable
• 若传递两个以上位置参数,则须为待比较元素 arg1 、 arg2 、 arg3 、…
…,第三个及以后元素以可变参数形式传递给 args
• 两个可选关键字参数: key 用于设置排序函数, default 用于在可迭代对
象为空时返回一个缺省值,而不是触发 ValueError 异常
• 若有多个最大值,函数返回处理过的第一个元素
• 函数 memoryview(obj) :返回给定对象的内存视图对象

18
3.1.3  内置函数
• 函数 min(iterable, *[, default, key]) 、 min(arg1, arg2, *args, *[,
key]) :返回数据集中元素的最小者
• 此为细化版本
• 参数的具体含义与 max() 相同
• 函数 next(iterator[, default]) :获取迭代器 iterator 的下一个
元素;若提供 default 参数,则在迭代器结束时返回该值,而
不是触发 StopIteration 异常
• 函数 class object() :返回一个新的无特征对象; object 类为
Python 全部类的基类

19
3.1.3  内置函数
• 函数 class open(file, mode = "r", buffering = -1, encoding =
None, errors = None, newline = None, closefd = True, opener =
None) :打开一个文件,返回一个文件对象; file 为可包括文件
路径的文件名, mode 为打开模式
• 函数 ord(c) :返回字符 c 的 Unicode 编码;函数 chr() 的
逆运算
• 函数 class property(fget = None, fset = None, fdel = None, doc =
None) :返回一个 property 属性
• 函数 repr(object) :返回对象 object 的可打印字符串表示
• 函数 reversed(seq) :返回一个逆向迭代器
20
3.1.3  内置函数
• 函数 class set([iterable]) :构造一个集合对象,其元素可以从
iterable 中选择
• 函数 setattr(object, name, value) :将对象 object 的 name 属
性设置为 value
• 函数 class slice(stop) 、 class slice(start, stop[, step]) :返回集合
的部分元素切片对象
• 函数 sorted(iterable[, key][, reverse]) :排序 iterable ,默认为
升序, reverse 设置为 True 时降序
• 函数 staticmethod(function) :返回 function 的类方法

21
3.1.3  内置函数
• 函数 class str(object = "") 、 class str(object = b"", encoding
= "utf-8", errors = "strict") :返回对象的字符串版本
• 函数 sum(iterable[, start]) :累加可迭代对象 iterable 的全部
元素与 start ,后者缺省值为 0
• 函数 super([type[, object-or-type]]) :返回代理对象,用于超类
调用
• 函数 tuple([iterable]) :构造一个元组; tuple 本质上是一种元
素内容不变的序列类型
• 函数 class type(object) 、 class type(name, bases, dict) :返回对
象 object 的类型对象或构造一个新类型对象
22
3.1.3  内置函数
• 函数 vars([object]) :返回模块、类、或对象的 __dict__ 属性
• 函数 zip(*iterables) :从多个可迭代对象中逐一抽取数据构造
元组迭代器,其中每个元组的元素均由可迭代对象的对应位置数
据构成,结果元组的实际元素数目由最短序列确定,较长序列的
多余元素被舍弃
• 函数 __import__(name, globals = None, locals = None, fromlist =
(), level = 0) :导入模块;不鼓励使用本函数,若要导入模块,
调用函数 importlib.import_module()

23
计算机程序设计基础( Python ) 24
3.1  函数调用
3.2  函数定义
3.3  名空间与作用域
3.4  函数参数
3.5  递 归
3.6  模 块

第三章 函数与模块 25
3.2  函数定义 26
3.2.1  函数定义规范
3.2.2  函数返回值
3.2.3   Lambda 表达式
3.2.4  函数标注
函数定义示例: Fibonacci 数列
• 函数定义示例:第〇章示例五
# Python 3.0 之后
# 函数定义,输出小于 n 的 Finonacci 数列元素
>>> def fib(n):
... """Print a Fibonacci series up to n."""
... a, b = 0, 1 # 多变量同时赋值
... while a < n: # 使用 while 循环输出数

... print(a, end = ' ') # 元素间以空格分隔
... a, b = b, a + b
... print()
...

27
3.2.1  函数定义规范
• 函数定义( definition ):给出函数具体实现
• 函数头与函数体
• 函数头:外部接口规范
• 函数头格式: def function_name([parameter_list]):
• 关键字 def 后跟函数名称和形式参数列表
• 形式参数列表可选;若存在,书写在小括号中,多个参数以逗
号分隔
• 函数体:内部业务逻辑
• 函数体内部代码必须整体缩进
28
函数定义示例:整数奇偶性
• 编写函数 odd_or_even() ,判断某个整数 n 是否为奇
数和偶数,输出其结果。
def odd_or_even(n):
if n % 2 == 1:
print(n, "is odd.")
else:
print(n, "is even.")

# 验证代码
n = eval(input("An integer: "))
odd_or_even(n)

29
函数定义非调用,无需 callee 已完工
• 函数定义非函数调用
• 函数定义并不执行函数体,函数体仅在函数调用时执行
• 函数只能调用已实现的函数,但函数定义时可“调用”未实现
的函数——函数定义顺序仅影响代码组织条理性
• 函数定义示例:双函数定义
def f(): # 定义函数 f() 可“调用”未实现的函数 g()
print("In function f")
g() # 因为此“调用”在未真正调用函数 f() 时不会发生
def g(): # 定义函数 g() ,确保其定义于函数 f() 实际调用之前
print("In function g")
f() # 实际函数调用,函数 f() 及其所需全部函数必须
已实现 30
嵌套函数
• 嵌套函数:在函数内部定义函数
• 内层函数仅供外层函数调用,外层函数之外不得调用
• 嵌套函数示例
def f(): # 外层函数 f()
print("Outer function f")
def g(): # 内层函数 g() ,仅供 f() 内部调用,必须定义在实际
调用前
print("Inner function g")
g() # 函数 f() 调用内层函数 g()
# 若函数 g() 定义与调用顺序颠倒,则引发 UnboundLocalError 异常
f() # 合法
f.g() # 非法,不得调用嵌套函数,引发 AttributeError 异常
31
程序设计辩证法:函数与数据
• 函数定义语句可执行
• 任务:在当前局部名空间( local namespace )或符号表
( symbol table )中引入函数名称,束定函数名称与函数对象
• 函数也是数据
• 一条函数定义定义一个用户自定义函数对象
• 访问函数对象:单独使用函数名称,无小括号
• 函数对象( function object, functor ):封装函数可执行代码
的打包器;含当前全局名空间( global namespace )的引用;
函数执行时需要使用该全局名空间
32
函数对象
• 函数对象类型:函数对象的值类型为用户自定义函数
• 函数对象赋值:函数名称可赋给其他量,后者也可作为
函数调用
>>> fib
<function fib at 0x1016b0b90>
>>> f = fib
>>> f
<function fib at 0x1016b0b90>
>>> f(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

33
3.2.2  函数返回值
• 函数返回值格式
• 语句: return 语句返回一个或多个对象或表达式,如 return
value 、 return 2 * 2
• 出现场合: return 语句只能出现在函数定义中
• 出现次数: return 语句可以多次出现或一次都不出现
• 无返回值函数
• 可以仅列写关键字 return 而无对象或表达式
• 没有或只有关键字 return 的函数“无”返回值
• 实际上,此时 Python 自动返回对象 None
34
3.2.2  函数返回值
• 函数返回逻辑
• 函数执行时,控制流在遇到第一条 return 语句时,进行其后
跟的表达式求值
• 函数终止执行,将该结果作为返回值传递给主调函数
• 主调函数可将返回值赋给其他数据对象
• 一种关注
• 异常处理中的 return 语句:当 return 语句出现在 try-
finally 语句的 suite-try 语句块中时,首先执行该函数的
suite-fin 语句块,函数随后才能终止执行
35
函数返回值示例:闰年判定
• 编写函数 is_leap() ,判定某个年份 year 是否为闰年。
def is_leap(year):
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0

36
函数返回值示例:整数奇偶性
• 编写两个函数 is_odd() 和 is_even() ,判断某个整数
n 是否为奇数和偶数。
def is_odd(n): def is_odd(n):
return n % 2 == 1 return bool(n & 1) # 需要转型

def is_even(n): def is_even(n):


return n % 2 == 0 return not n & 1 # 已自动转

37
返回函数对象
• 函数返回值可以为函数对象
• 通过该函数对象调用其引用的函数
• 可返回嵌套定义的函数,从而在嵌套函数外部调用之
def f(): # 外层函数 f()
print("Outer function f")
def g(): # 内层函数 g()
print("Inner function g")
return g # 外层函数 f() 返回内层函数 g , f() 为 g() 的
包装函数
h = f() # 调用函数 f() ,获得其返回的函数对象
h() # 合法,通过 h 执行内层函数 g() 代码
f()() # 合法,省略量 h 定义
38
3.2.3   Lambda 表达式
• 格式: lambda [parameter_list]: expression
• 等价于如下定义:
def function_name(parameter_list):
return expression
• Lambda 表达式目的与意义
• 创建一个匿名函数,返回函数对象
• 函数代码一般极短:用于一行表达式即可解决问题的场合
• 适用于任何需要函数对象的场合

39
Lambda 表达式示例
# 示例一
>>> f = lambda a, b: a + b
>>> type(f)
<class 'function'>
>>> f(1, 2)
3
# 示例二
>>> def inc(base):
... return lambda x: base + x
...
>>> f = inc(42) # 使用 f 引用 inc() 返回的函数对象 , base 为
42
>>> f(42) # 42 被累加到 base 上
84 40
3.2.4  函数标注
• 函数标注( annotation )目的
• 提供用户自定义函数所使用的类型元信息
• 函数标注格式
• 参数类型标注使用“ :” 加类型名称,函数返回值类型标准使
用“ ->” 加类型名称
• 示例: def Add(x: int, y: int = 0) -> int: return x + y
• 一种关注
• 在 Python 3.6 中,函数标注为可选选项,对函数其他部分无
任何影响
41
函数定义示例:素性判定
• 编写函数 is_prime() ,判断正整数 n (n≥2) 素性。
def is_prime(n: int) -> bool:
import math
if type(n) is not int:
raise TypeError('must be an integer, but "%s" found' % type(n))
if n < 2:
raise ValueError('must be greater than 1, but "%d" found' % n)
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, math.ceil(math.sqrt(n)) + 1, 2):
if n % i == 0:
return False
return True

42
计算机程序设计基础( Python ) 43
3.1  函数调用
3.2  函数定义
3.3  名空间与作用域
3.4  函数参数
3.5  递 归
3.6  模 块

第三章 函数与模块 44
3.3  名空间与作用域 45
3.3.1  名空间
3.3.2  作用域
3.3.3  全局量与局部量
3.3.4   global 与 nonlocal
3.3.1  名空间
• 名空间:从名称到对象的映射
• 实现上,大多数名空间表现为符号表,以字典的形式组织,而
变量存储其中
• Python 脚本中存在多个相互独立的名空间
• 名空间特性
• 标识符独立性:不同名空间的同名标识符没有任何关联
• 标识符唯一性:同一名空间中的标识符不得重名
• 名空间嵌套:一个名空间可以包含另外一个名空间
• 主要来源:嵌套函数定义、类成员函数

46
名空间分类
• 内置名空间( built-in namespace )
• 内置名称集合,如内置函数名、内置异常名等
• 全局名空间
• 模块内部的全局名称集合
• 局部名空间
• 函数调用时的本地名称集合;对象的属性集合;嵌套函数的本
地名称集合;类成员函数的本地名称集合
• 不同函数调用使用不同名空间,如递归

47
名空间生存期
• 内置名空间
• 创建时间: Python 解释器启动时
• 删除时间: Python 解释器退出时
• 模块全局名空间
• 创建时间:读入模块定义时
• 删除时间:正常情况下,在 Python 解释器退出时
• 注意事项:全局仅指在该模块内部为全局的;每个模块都有独
立的全局名空间;导入模块后方可访问其中的全局标识符;模
块中可能存在非全局标识符,即使导入模块也不可访问
48
名空间生存期
• 函数名空间
• 创建时间:调用函数时
• 删除时间:函数结束时,函数引发异常但却未在本函数内处理
该异常时
• 类名空间
• 创建时间:构造对象时
• 删除时间:销毁对象时

49
名空间解析
• 名解析:属性操作符“ .” 解析不同名空间中的标识符
• 名解析示例
• 导入模块一般情况下不会引起名冲突(不一般的情况呢?)
>>> e = 1
>>> import math
>>> print(e) # 第一行定义的普通变量
1
>>> print(math.e) # 数学模块中自然对数
2.718281828459045

用 from math import e 方式导入自然对数,将和变量 e 重名


50
3.3.2  作用域
• 作用域( scope )概念
• 定义:可访问名空间中标识符的文法区域
• 表现形式:在 Python 程序文本的某处,是否可以使用该名
空间中的标识符
• 作用域与名空间的关系
• 不在某名空间中,不能访问名该空间中的标识符
• 在某名空间中,不一定能访问该名空间中的标识符
• 主要原因:嵌套的名空间中的同名标识符可能导致名冲突

51
作用域分类与标识符查找
• 作用域分类
• 局部作用域(最内层):函数(类成员函数)、类、 Lambda
表达式形成的文法区域
• 外层函数闭包作用域:嵌套函数的外层函数形成的文法区域
• 注意:有可能存在多层嵌套
• 全局作用域:模块形成的文法区域
• 用户程序所在的模块为主模块 __main__
• 内置作用域(最外层):包含内置名称的文法区域
• 标识符查找顺序:由内向外
52
3.3.3  全局量与局部量
• 局部量
• 定义于函数、类成员函数与 Lambda 表达式中的量
• 类的数据属性:定义于类中,其表现与访问规则与局部量类似
• 形式参数类似局部量,但因参数传递原因,有细微差异
• 全局量
• 定义于类、函数、类成员函数与 Lambda 表达式之外的场合
• 名空间与作用域对量定义的影响
• 全局量与局部量位于不同名空间,因而可重名
• 发生重名时,局部量可能遮盖全局量的作用域,使其不可见
53
全局量与局部量示例
n = 42 # n 为全局量,位于全局名空间,其后代码(包括函数内部)均可访问

def double(x): # 形式参数 x 也为局部量,位于局部名空间,函数内部可访问


# 访问全局量 n
print( "Before being doubled in double(): n = ", n )
m = x * 2 # m 为局部量,位于局部名空间,函数内部可访问
print( "After being doubled in double(): m = ", m )
print( "After being doubled in double(): n = ", n )
return m

print( "Before calling double() in __main__: n = ", n )


m = double(n) # m 为全局量,位于全局名空间,与函数内部 m 为独立的两个
对象
print( "After calling double() in __main__: m = ", m )
print( "After calling double() in __main__: n = ", n )
54
全局量与局部量示例
# 程序输出结果

# 调用函数前,全局量 n 值为 42
Before calling double() in __main__: n = 42
# 调用函数中,全局量 n 值为 42 (加倍前)
Before being doubled in double(): n = 42
# 调用函数中,局部量 m 值为 84 (加倍后)
After being doubled in double(): m = 84
# 调用函数中,全局量 n 值为 42 (加倍后)
After being doubled in double(): n = 42
# 调用函数后,全局量 m 接受加倍值 84
After calling double() in __main__: m = 84
# 调用函数后,全局量 n 值维持 42 不变
After calling double() in __main__: n = 42

55
全局量与局部量示例
n = 42 # n 为全局量,位于全局名空间,其后代码(包括函数内部)均可访问
def double(x):
# 注释下一条语句,否则无法束定局部量 n ,引发 UnboundLocalError 异常
# print( "Before being doubled in double(): n = ", n )
# 定义同名局部量 n (赋值即定义),新对象具有局部作用域,整个函数内部均有效
# 局部量 n 遮盖同名全局量 n 的部分作用域,使其不可见
# 局部量 n 定义前虽不能访问,但仍不允许上条注释语句访问全局量 n
# 换言之,即使前述注释语句出现在局部量 n 定义之前, n 也被解释为局部量
n = x * 2
print( "After being doubled in double(): n = ", n )
return n
print( "Before calling double() in __main__: n = ", n )
m = double(n)
print( "After calling double() in __main__: m = ", m )
print( "After calling double() in __main__: n = ", n )
56
全局量与局部量示例
# 程序输出结果

# 调用函数前,全局量 n 值为 42
Before calling double() in __main__: n = 42
# 调用函数中,局部量 n 值为 42
After being doubled in double(): n = 84
# 调用函数中,全局量 m 接受加倍值 84
After calling double() in __main__: m = 84
# 调用函数后,全局量 n 维持原值 42 不变
# 即全局量 n 与局部量 n 虽同名,但不是同一对象
After calling double() in __main__: n = 42

57
3.3.4   global 与 nonlocal
• 问题:如何在函数内部修改全局量的值
• 在函数内部可以引用全局量,但不能赋值——赋值将定义同名
局部量
• 进一步地,发生函数嵌套时,如何在内层函数中修改外层函数
定义的局部量的值?
• 解决方案:量声明
• 全局声明( global declaration )
• 非局部声明( nonlocal declaration )

58
全局声明
• 全局声明:使用 global 关键字
• 声明格式: global identifier
• 多标识符全局声明:使用逗号分隔
• 全局声明中的标识符不得为形式参数、不得位于 for 循环目
标列表、类定义、函数定义、导入语句或变量标注中
• 含义:将其后标识符解释为全局的
• 若该标识符在全局未定义,则此声明定义之,该全局量在函数
调用结束后保持有效
• 有效性:在当前代码块各处均有效(包括声明之前)
59
全局声明示例
n = 42 # n 为全局量,位于全局名空间,其后代码(包括函数内部)均可访问

def double(): # 直接使用全局量 n ,无需传递参数


global n # 声明全局量 n ,函数内部对其赋值不会构造新的局部对象
print( "Before being doubled in double(): n = ", n )
n = n * 2 # 直接写入全局量
print( "After being doubled in double(): n = ", n )
return n

print( "Before calling double() in __main__: n = ", n )


m = double()
print( "After calling double() in __main__: m = ", m )
print( "After calling double() in __main__: n = ", n )

60
全局量与局部量示例
# 程序输出结果

# 调用函数前,全局量 n 值为 42
Before calling double() in __main__: n = 42
# 调用函数中,全局量 n 值为 42 (加倍前)
Before being doubled in double(): n = 42
# 调用函数中,全局量 n 值更新为 84 (加倍后)
After being doubled in double(): n = 84
# 调用函数后,全局量 m 接受加倍值 84
After calling double() in __main__: m = 84
# 调用函数后,全局量 n 维持更新后的值 84 不变
After calling double() in __main__: n = 84

61
非局部声明
• 非局部声明:使用 nonlocal 关键字
• 声明格式: nonlocal identifier
• 多标识符全局声明:使用逗号分隔
• 含义:将其后标识符解释为非局部非全局的
• 从最内层嵌套名空间向外查找,一直到全局名空间(不含)
• 若未找到该标识符,引发 SyntaxError 异常
• 有效性:在当前代码块各处均有效(包括声明之前)
• 非局部声明的用法类似全局声明

62
计算机程序设计基础( Python ) 63
3.1  函数调用
3.2  函数定义
3.3  名空间与作用域
3.4  函数参数
3.5  递 归
3.6  模 块

第三章 函数与模块 64
3.4  函数参数 65
3.4.1  参数传递机制
3.4.2  缺省参数值
3.4.3  位置参数与关键字参数
3.4.1  参数传递机制
• 形式参数( formal parameter/augment )与实际参数
( actual parameter/augment )
• 形式参数:函数定义时提供的参数
• 实际参数:函数调用时提供的参数
• 参数传递( parameter passing )
• 函数调用时,需要将实际参数传递给形式参数
• 对象共享机制: Python 参数传递时不构造新数据对象,而是
让形式参数和实际参数共享同一对象
• 构造新对象时机:函数内部变更有常对象值时(写时复制)
66
参数传递机制示例
n = 2 # 在主模块 __main__ 中构造整型对象 2 ,将名称 n 束定于其上
# 定义函数 double() ,加倍整数 x
def double(x): # 函数调用时,名称 x 同样束定于整型对象 2 之上
# 函数内部进行表达式求值,需要重新设定 x 的值
x *= 2 # 2 为有常对象,值无法变更
# Python 构造一个新的整型对象 4 ,解除 x 的束定,重新束定其于新对象之

return x # 返回新对象
# 调用函数 double() 时,实际参数 n 传递给形式参数 x ,
# 使得函数 double() 内部的名称 x 同样束定于主模块的整型对象 2 之上,
# 此时并未构造一个新的整型对象
m = double(n)
print("m =", m)
print("n =", n) 67
参数传递机制示例
# 调用函数 id() 查看对象本征值
n = 2
print("id(n):", id(n))
def double(x):
print("In double(): id(x):", id(x))
x *= 2
print("In double(): id(x):", id(x))
return x
m = double(n)
print("m =", m)
print("id(m):", id(m))
print("n =", n)
print("id(n):", id(n))
68
参数传递机制示例
# 脚本输出
id(n): 1381737600
In double(): id(x): 1381737600
In double(): id(x): 1381737664
m = 4
id(m): 1381737664
n = 2
id(n): 1381737600

69
3.4.2  缺省参数值
• 缺省参数值( default augment value )定义格式
• 函数定义: def multiply(x, times = 2): return x * times
• 函数调用: a = multiply(42) 与 b = multiply(42, 42)
• 带缺省参数值的函数定义规范
• 参数数目:无限制
• 普通非缺省参数不得出现在此类参数之后
• 函数定义时,必须普通非缺省参数在前,带缺省参数值的参数在后

70
3.4.2  缺省参数值
• 带缺省参数值的函数调用规范
• 双参数调用函数 multiply() :实际参数按照函数定义时的位
置顺序分别传递给形式参数 x 与 times
• 单参数调用函数 multiply() :实际参数传递给 x , times 使
用缺省值 2
• 参数传递顺序:当存在多个缺省参数值时,函数调用时必须按
照位置顺序提供非缺省值,不能跳过部分缺省参数值
• 示例:有函数定义 def f(x, y = 1, z = 1): pass ,用 f(a) 、 f(a,
b) 、 f(a, b, c) 方式调用均合法,但用 f(a, , c) 方式调用非法

71
3.4.2  缺省参数值
• 缺省参数值意义:简化函数接口
• 当函数部分参数大概率为某个固定值时,使用缺省参数值可以
简化函数调用接口,提高编程效率和代码可理解性
• 一种关注
• 缺省参数值技术可以部分实现函数重载( overloading )效果
• 对于有缺省参数值的函数,其调用在外观上存在多个“不同”版本,具
有一定的函数重载效果
• 但是,这并不是真正的函数重载—— Python 语言目前不支持函数重载,
未来可能也不会支持—— Python 中实际上有其他技术手段实现类似函
数重载的功能

72
插播:缺省参数存在的问题与解决方案
• 缺省参数值的问题:高能预警!
• 缺省参数值计算时机:只在函数定义时计算一次
• 缺省参数值为表达式或无常对象时,如果其值在后续操作过程
中发生变化,有可能导致不希望的结果
• 示例:对于列表对象,下述代码导致列表元素累积
def f(a, ls = []):
ls.append(a)
return ls
print(f(1)) # 输出 [1]
print(f(2)) # 输出 [1, 2]
print(f(3)) # 输出 [1, 2, 3]
73
插播:缺省参数存在的问题与解决方案
• 对症下药
• 原因分析: ls 的缺省值在函数定义时计算,构造一个空列表
对象,其后所有函数调用都引用此列表对象,元素自然累积
• 解决方案:使用 None 作为列表对象的缺省值,并在函数内
部设置哨兵( sentinel ),监视其变化
def f(a, ls = None):
if ls is None: # 本条 if 语句等价于 ls = ls or []
ls = [] # 当 ls 为 None 时(函数调用时无第二个
参数),
ls.append(a) # 真值测试为 False ,构造空列表对象并赋值,
return ls # 否则引用原先的列表对象
74
综合示例:整数输入的有效性检查
• 编写函数 input_int() ,接受用户输入的整数,并检查
返回数据的有效性。函数执行时应输出提示信息;若用
户未提供该信息,函数应使用缺省信息提示用户。

75
综合示例:整数输入的有效性检查
def input_int(prompt: str = None) -> int:
t = input(prompt or "Please input an integer: ")
while True:
# 尝试转换为整数,非整数时引发异常;处理该异常,请求用户重新输入
# 得到合法数据, return 语句跳出无限循环,返回合法整数
try:
return int(t)
except ValueError:
t = input("An integer needed. Try again: ")
m = input_int("Your age: ")
print(m)
n = input_int()
print(n)
76
3.4.3  位置参数与关键字参数
• 位置参数( positional parameter )
• 位置固定:参数传递时按照形式参数定义顺序提供实际参数
• 缺点:参数数目较多时,函数调用时容易混淆;缺省参数数目
较多时,提供非缺省值时不能跳跃
• 关键字参数( keyword parameter )
• 在函数调用时,提供实际参数对应的形式参数名称
• 优点:明确标示实际参数和形式参数的对应关系;参数书写顺
序更灵活
• 缺点:增加函数调用时的代码书写量
77
关键字参数语法规范
• 关键字参数格式: formal_parameter = expression
• 关键字参数使用场合
• 仅函数调用时,函数定义与其无关
• 关键字参数示例
• 函数定义: def f(x, y = 1, z = 1): ……
• 以 f(a, z = c) 方式调用: a 以位置参数传递, c 以关键字参
数传递,第二个参数使用缺省值

78
关键字参数使用原则
• 关键字参数适用性
• 普通参数和缺省参数均适用
• 关键字参数使用限制
• 关键字参数必须位于位置参数之后
• 关键字参数必须与函数定义时的形式参数名称匹配
• 关键字参数顺序无限制
• 不得重复提供实际参数

79
关键字参数使用示例
def f(x, y = 0, z = 0): pass # 空语句,定义空函数体
f(1, 2, 3) # 合法
f(1, 2) # 合法, z 使用缺省参数值
f(1) # 合法, y 与 z 使用缺省参数值
f(1, , 3) # 非法, y 为缺省参数, z 也必须缺省
f(1, y = 2, z = 3) # 合法, y 与 z 为关键字参数
f(1, z = 3) # 合法, y 使用缺省参数值
f(x = 1, y = 2, z = 3) # 合法,均为关键字参数
f(z = 3, x = 1, y = 2) # 合法,顺序无所谓
f(x = 1, z = 3) # 合法, x 与 z 为关键字参数, y 缺省
f(1, x = 1, z = 3) # 非法,不得重复提供参数 x
f(x = 1, 2) # 非法,关键字参数后不得有位置参数
f(1, y = 2, t = 3) # 非法,关键字参数 t 不存在
80
计算机程序设计基础( Python ) 81
3.1  函数调用
3.2  函数定义
3.3  名空间与作用域
3.4  函数参数
3.5  递 归
3.6  模 块

第三章 函数与模块 82
3.5  递 归 83
3.5.1  递归函数
3.5.2  递归信任
3.5.3  汉诺塔
3.5.1  递归函数
• 单函数递归
• 递推公式:数学上极为常见
• 例一:阶乘函数:
• 例二: Fibonacci 数列:
• 双函数递归
• 函数 f() 调用函数 g() ,而函数 g() 又调用函数 f()
• 比较少见

84
递归工作原理
• 递归函数特征
• 递推函数一定是分段函数,具有初始表达式
• 递推函数计算逻辑:逐步简化问题规模
• 递归工作原理
• 递推过程:逐步分解问题,使其更简单
• 回归过程:根据简单情形组装最后的答案

85
3.5.1  递归函数
• 实现函数 fact() ,使用循环和递归两种方法求非负整
数 n 的阶乘。
# 循环实现 # 递归实现
def fact(n): def fact(n):
if n <= 1: return n * fact(n-1) if n > 1 else 1
return 1
r, i = 1, 2 # 验证代码,输出前 12 项
while i <= n: for i in range(12):
r *= i print(fact(i), sep = '')
i += 1
return r # Honestly, do you think which one is better?
# 输出结果如下:
1 1 2 6 24 120 720 5040 40320 362880 3628800 39916800
86
3.5.1  递归函数
• 实现函数 fib() ,使用循环和递归两种方法求
Fibonacci 数列的第 n 项, n 为非负整数。
# 循环实现 # 递归实现
def fib(n): def fib(n):
if n <= 1: return fib(n-1) + fib(n-2) if n > 1 else n
return n
a, b = 0, 1
i = 2 # 验证代码,输出前 20 项
while i <= n: for i in range(20):
a, b = b, a + b print(fib(i), end = ' ')
i += 1
return b # Now you tell me!
# 输出结果如下:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
87
3.5.2  递归信任
• 关于递归与循环的基本结论
• 理论上,任何递归程序都可以使用循环迭代方法解决
• 递归函数代码更短小精悍
• 一旦掌握递归思考方法,递归比循环更易理解
• 递归与循环比较
项 目 循 环 递 归
代码重复执行 显式循环结构 重复函数调用
终止执行时机 满足循环终止条件 问题简化到最简情形
重复时机 当前迭代结束 调用同名函数
可能隐含的程序缺陷 条件永真,无限循环 无法退化,无穷递归
88
3.5.2  递归信任
• 递归信任:要相信递归能够正确工作——
• 就像相信数学归纳法能够正确工作一样
• 就像相信太阳明天照常升起一样!
• 培养递归信任的六大基础原则
• 递归实现是否检查最简单情形
• 递归函数几乎总有 if 语句,且最先执行;若否,请仔细检查源程序
• 最简单情形是否正确解决
• 大量递归错误由未正确解决最简单情形引起
• 最简单情形不能调用递归

89
3.5.2  递归信任
• 培养递归信任的六大基础原则
• 递归分解是否使问题更简单
• 若否,则容易形成无限递归,算法无法终止
• 问题简化过程是否能回归最简单情形,是否遗漏某些情况
• 部分程序需要两次或多次递归调用;遗漏任意一个都会导致错误
• 子问题是否与原始问题完全一致
• 递归过程不可改变问题性质,否则必然错误
• 子问题的解是否正确组装
• 只有正确组装,才能形成原问题的答案

90
3.5.3  汉诺塔
• 汉诺塔( Hanoi )问题描述
• 有三个分别命名为 X 、 Y 和 Z 的塔座,塔座 X 上有 n
个直径大小不同、从小到大分别编号为 1, 2, ..., n 的圆盘,如
图所示:

X Y Z

91
3.5.3  汉诺塔
• 编程任务:
• 将塔座 X 上的 n 个圆盘移动到塔座 Z 上
• 移动时遵循下述规则:一、每次仅能移动单个圆盘;二、圆盘
可放置在 X 、 Y 与 Z 中的任意塔座上;三、任何时刻都不
能将较大圆盘放在较小圆盘上
• 演示视频: Hanoi.flv

92
3.5.3  汉诺塔
• 待解决问题
• Q1 :是否存在某种简单情形,问题很容易解决
• Q2 :是否可将原问题分解成性质相同但规模较小的子问题,
且新问题的解答对原始问题有关键意义
• 解答方案
• A1 :只有一个圆盘
• A2 :对于 n > 1 ,先将 n - 1 个圆盘移动到塔座 Y 上,然
后将第 n 个圆盘移动到 Z 上,最后将 n - 1 个圆盘从 Y
上移动到 Z 上
93
3.5.3  汉诺塔
# 将 n 个圆盘从 x 以 y 为中转移动到 z
def move(n = 8, x = "X", y = "Y", z = "Z"):
# 移动单个圆盘;嵌套函数定义,单行函数体,可并行书写
def move_one(n, x, z): print(n, "from", x, "to", z)
if n < 1:
return
if n == 1:
move_one(1, x, z)
else:
move(n - 1, x, z, y)
move_one(n, x, z)
move(n - 1, y, x, z)
return
94
3.5.3  汉诺塔
# 整数输入函数
def input_int(prompt: str = None) -> int:
t = input(prompt or "Please input an integer: ")
while True:
try:
return int(t)
except ValueError:
t = input("An integer needed. Try again: ")
return

# 验证代码
n = input_int("Number of towers: ")
move(n) # n 值不能过大!否则会没完没了……
95
3.5.3  汉诺塔
# 程序执行结果 # 程序执行结果
Number of towers: 3 Number of towers: 4
1 from X to Z 1 from X to Y
2 from X to Y 2 from X to Z
1 from Z to Y 1 from Y to Z
3 from X to Z 3 from X to Y
1 from Y to X 1 from Z to X
2 from Y to Z 2 from Z to Y
1 from X to Z 1 from X to Y
4 from X to Z
1 from Y to Z
2 from Y to X
1 from Z to X
3 from Y to Z
1 from X to Y
2 from X to Z
1 from Y to Z
96
计算机程序设计基础( Python ) 97
3.1  函数调用
3.2  函数定义
3.3  名空间与作用域
3.4  函数参数
3.5  递 归
3.6  模 块

第三章 函数与模块 98
3.6  模 块 99
3.6.1  模块•包•库
3.6.2  日期时间模块
3.6.3  随机数模块
3.6.4  海龟作图模块
3.6.1  模块•包•库
• 模块( module )
• 定义:包含 Python 定义和语句的文本文件(脚本)
• 名称:模块文件名(不含扩展名“ .py” )
• 在模块内部,使用全局变量 __name__ 获得模块名称字符串
• 包( package )
• 定义:包含 __path__ 属性的模块集合
• 库( library ):非 Pyhton 专有词汇
• 定义:完成特定功能的代码集合

100
模块目的与性质
• 模块目的
• 组织 Python 代码的对象
• 一次定义,多次使用
• 模块性质
• 模块中的 Python 对象位于模块全局名空间(私有符号表)
• 模块可以包含或递归包含子模块
• 模块必须导入方可使用
• 模块可导入其他模块

101
模块内容
• 可执行语句
• 目的:主要用于初始化模块
• 执行时机:导入语句首次解析模块名称时
• 全局变量
• 目的:模块内部定义的量,主要用于描述模块状态
• 在模块外部,可使用 modulename.variablename 格式访问
• 函数定义
• 目的:代码重用
• 在模块外部,可使用 modulename.functionname() 格式调用
102
自定义模块示例
# 模块脚本文件“ mymod.py”
################################################################
# 可导出函数
################################################################

def input_int(prompt: str = None) -> int:


"""Get an integer safely.

If the augument prompt is None or omitted,


the function shows default hint.
"""
t = input(prompt or "Please input an integer: ")
while True:
try:
return int(t)
except ValueError:
t = input("An integer needed. Try again: ")
103
自定义模块示例
def is_leap(year):
"""Determine whether a year is leap

Return True if the augument year is leap, otherwise False.


The augument must be a positive integer.
"""
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0

def is_odd(n):
"""Determine whether an integer is odd

Return True if the augument year is odd, otherwise False.


The augument must be an integer.
"""
return bool(n & 1)

104
自定义模块示例
def is_even(n):
"""Determine whether an integer is even

Return True if the augument year is even, otherwise False.


The augument must be an integer.
"""
return not n & 1

def is_prime(n: int) -> bool:


"""Determine whether an integer is a prime number

Return True if the augument year is a prime, otherwise False.


Raise TypeError exception if the augument is not an integer;
Raise ValueError exception if the augument is less than 2.
"""

105
自定义模块示例
import math
if type(n) is not int:
raise TypeError('must be an integer, but "%s" found' % type(n))
if n < 2:
raise ValueError('must be greater than 1, but "%d" found' % n)
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, math.ceil(math.sqrt(n)) + 1, 2):
if n % i == 0:
return False
return True

106
自定义模块示例
def fact(n):
"""Factorial function.

Get the factorial number of the augument n.


The augument must be a non-negative integer.
"""
return n * fact(n-1) if n > 1 else 1

def fib(n):
"""Fibonacci function.

Get the n-th item of Fibonacci series.


The augument must be a non-negative integer.
"""
return fib(n-1) + fib(n-2) if n > 1 else n

107
自定义模块示例
################################################################
# 全局变量
################################################################

a_global_var_for_test = 2

################################################################
# 内部变量
#
# 使用 __xxx__ 格式以防止导出全局标识符,或者使用旧式规范:标识符前使用单下划线,
# 以表明该全局标识符为模块非公开的。
# 注意:仅是习惯性建议。在模块外界依然可以使用这些“内部变量”。
################################################################

__a_private_var_for_test__ = 2

108
自定义模块示例
################################################################
# 测试语句
#
# 仅用于独立测试;当本模块被其他模块导入时,将跳过测试语句的执行。
# 单独执行模块时,模块名称总是 __main__ 。仅在本模块被导入时,名称才是其本名。
################################################################

if __name__ == "__main__":
print("Testing", __name__)
__a_private_var_for_test__ = input_int("Your age: ")
print("Your age is", __a_private_var_for_test__)

# 使用命令“ python mymod.py” 单独测试模块时输出


Testing __main__
Your age: 20
Your age is 20

109
自定义模块示例
# 脚本文件“ mymod_test.py”
import mymod

print("The name of the module is \"%s\"" % mymod.__name__)


print("a_global_var_for_test is", mymod.a_global_var_for_test)
print("__a_private_var_for_test__ is", mymod.__a_private_var_for_test__)
n = mymod.input_int("Your age: ")
print("Your age is", n)

# 脚本输出
The name of the module is "mymod"
a_global_var_for_test is 2
__a_private_var_for_test__ is 2
Your age: 20
Your age is 20

110
3.6.2  日期时间模块
• 日期时间模块 datetime
• 功能:日期与时间处理
• 日期时间对象分类
• 单纯( naive )日期时间对象
• 无时区和夏时制信息
• 是否为通用协调时间( Universal Time Coordinated , UTC )或当地时
间,是否具有时区信息取决于程序
• 敏感( aware )日期时间对象
• 具有时区和夏时制信息

111
日期时间模块常数与类型
• 可用常数
• 常数 datetime.MINYEAR : date 与 datetime 对象最小年份,
值为 1
• 常数 datetime.MAXYEAR : date 与 datetime 对象最大年
份,值为 9999
• 可用类型
• 类 datetime.date :单纯日期类,属性 year 、 month 与 day
• 类 datetime.time :独立时间类,属性
hour 、 minute 、 second 、 microsecond 与 tzinfo

112
日期时间模块常数与类型
• 可用类型
• 类 datetime.datetime :日期时间类组合,属性
year 、 month 、 day 、 hour 、 minute 、 second 、 microsec
ond 与 tzinfo
• 类 datetime.timedelta :时段类,两个 date 、 time 或
datetime 对象间的时间间隔,精确到微秒
• 类 datetime.tzinfo :时区信息抽象基类,用于 time 或
datetime 对象进行时间调整
• 类 datetime.timezone :时区信息类,相对 UTC 进行时区调

113
日期对象
• 日期对象构造
• 日期对象构造函数 class datetime.date(year, month, day) :以
给定年月日信息构造日期对象
• 类方法 classmethod date.today() :返回当前本地日期
• 类方法 classmethod date.fromtimestamp(timestamp) :返回
相对 POSIX 时间戳的本地日期
• 可能引发 OverflowError 或 OSError 异常;年份可能受限于 1970
至 2038
• 类方法 classmethod date.fromordinal(ordinal) :以序数值构
造日期,公元 1 年 1 月 1 日值为 1 ,此后依次递增
114
日期对象构造示例
>>> import datetime
>>> d1 = datetime.date(1582, 10, 4)
>>> n1 = d1.toordinal() # 转换为序数
>>> n1
577725
>>> d2 = datetime.date(1582, 10, 15)
>>> n2 = d1.toordinal()
>>> n2
577736
>>> d3 = datetime.date.today()
>>> d3
datetime.date(2017, 3, 29)

115
日期对象
• 日期类属性
• 属性 date.min :最早可表示日期 date(MINYEAR, 1, 1)
• 属性 date.max :最晚可表示日期 date(MAXYEAR, 12, 31)
• 属性 date.resolution :最小日期差值 timedelta(days = 1)
• 日期对象属性
• 属性 date.year :年
• 属性 date.month :月
• 属性 date.day :日

116
日期对象
• 日期对象运算
• 加法操作 date2 = date1 + timedelta :加上间隔时段,忽略
timedelta 的秒和微秒;可能引发 OverflowError 异常
• 减法操作 date2 = date1 - timedelta :减去间隔时段,忽略
timedelta 的秒和微秒;可能引发 OverflowError 异常
• 减法操作 timedelta = date1 - date2 :获取间隔时段,
timedelta 的秒和微秒设为 0
• 比较操作 date1 < date2 :日期比较;可能引发 TypeError
异常

117
日期对象
• 日期对象方法
• 方法 date.replace(year = self.year, month = self.month, day =
self.day) :返回给定日期对象,可使用参数更新日期值
• 方法 date.timetuple() :返回时间结构,包含年月日时分秒与
星期等信息
• 方法 date.toordinal() :返回日期序数
• 方法 date.weekday() :返回星期信息,周一为 0 ,周日为
6
• 方法 date.isowekday() :返回 ISO 星期信息,周一为 1 ,
周日为 7
118
日期对象
• 日期对象方法
• 方法 date.isocalendar() :返回 ISO 日历三元组
• 方法 date.isoformat() :返回 ISO 日期字符串,格式
为“ YYYY-MM-DD”
• 方法 date.__str__() :返回日期字符串,与方法
date.isoformat() 等价
• 方法 date.ctime() :返回日期字符串
• 方法 date.strftime(format) :以特定格式返回日期字符串
• 方法 date.__format__(format) :与上一方法功能相同
119
日期对象使用示例
>>> d = datetime.date.today()
>>> d
datetime.date(2017, 3, 29)
>>> t = d.timetuple()
>>> for i in t:
... print(i)
...
2017 # 年
3 # 月
29 # 日
0 # 时
0 # 分
0 # 秒
2 # 周三(周一为 0 )
88 # 本年度第 88 天
-1 # 非夏时制

120
日期时间对象
• 日期时间对象构造
• 日期时间对象构造函数 class datetime.datetime(year, month,
day, hour = 0, minute = 0, second = 0, microsecond = 0, tzinfo =
None, *fold = 0) :以给定信息构造日期时间对象
• 类方法 classmethod datetime.today() :返回当前本地日期时

• 类方法 classmethod datetime.now(tz = None) :返回当前本
地日期时间,可设置时区
• 类方法 classmethod datetime.utcnow() :返回当前 UTC 日
期时间
121
日期时间对象
• 日期时间对象构造
• 类方法 classmethod datetime.fromtimestamp(timestamp, tz =
None) :返回相对 POSIX 时间戳的本地日期时间,可设置时

• 可能引发 OverflowError 或 OSError 异常;年份可能受限于 1970
至 2038
• 类方法 classmethod
datetime.utcfromtimestamp(timestamp) :返回相对 POSIX
时间戳的 UTC 日期时间
• 可能引发 OverflowError 或 OSError 异常;年份可能受限于 1970
至 2038
122
日期时间对象
• 日期时间对象构造
• 类方法 classmethod datetime.fromordinal(ordinal) :以序数
值构造日期时间,公元 1 年 1 月 1 日值为 1 ,时分秒微
秒为 0 ,时区为 None ,此后依次递增
• 类方法 classmethod datetime.combine(date, time, tzinfo =
self.tzinfo) :组合日期与时间对象
• 类方法 classmethod datetime.strptime(date_string,
format) :以格式 format 解析日期字符串 date_string ,构
造相应日期时间对象

123
日期时间对象
• 日期时间类属性
• 属性 datetime.min :最早可表示日期时间 date(MINYEAR,
1, 1, tzinfo = None)
• 属性 datetime.max :最晚可表示日期时间
date(MAXYEAR, 12, 31, 23, 59, 59, 999999, tzinfo = None)
• 属性 datetime.resolution :最小日期时间差值
timedelta(microseconds = 1)
• 日期时间对象属性
• 属性 datetime.year :年

124
日期时间对象
• 日期时间对象属性
• 属性 datetime.month :月
• 属性 datetime.day :日
• 属性 datetime.hour :时(二十四时制)
• 属性 datetime.minute :分(六十分制)
• 属性 datetime.second :秒(六十秒制)
• 属性 datetime.microsecond :微秒(百万微秒制)
• 属性 datetime.tzinfo :时区
• 属性 datetime.fold :夏时制标志
125
日期时间对象
• 日期时间对象运算
• 加法操作 datetime2 = datetime1 + timedelta :加上间隔时段,
忽略 timedelta 的秒和微秒;可能引发 OverflowError 异常
• 减法操作 datetime2 = datetime1 - timedelta :减去间隔时段,
忽略 timedelta 的秒和微秒;可能引发 OverflowError 异常
• 减法操作 timedelta = datetime1 - datetime2 :获取间隔时段,
timedelta 的秒和微秒设为 0
• 比较操作 datetime1 < datetime2 :日期比较;可能引发
TypeError 异常

126
日期时间对象
• 日期时间对象方法
• 方法 datetime.date() :返回日期对象
• 方法 datetime.time() :返回时间对象
• 方法 datetime.timetz() :返回时区对象
• 方法 datetime.replace(year = self.year, month = self.month,
day = self.day, hour = self.hour, minute = self.minute, second =
self.second, microsecond = self.microsecond, tzinfo = self.tzinfo,
*fold = 0) :返回给定日期时间对象,可使用参数更新日期时
间值

127
日期时间对象
• 日期时间对象方法
• 方法 datetime.astimezone(tz = None) :返回新的日期时间对
象,以新时区构造该对象, UTC 日期时间与原对象相同
• 方法 datetime.utcoffset() :若 tzinfo 为 None ,返回
None ,否则返回 self.tzinfo.utcoffset(self)
• 方法 datetime.dst() :若 tzinfo 为 None ,返回 None ,否
则返回 self.tzinfo.dst(self)
• 方法 datetime.tzname() :若 tzinfo 为 None ,返回
None ,否则返回 self.tzinfo.tzname(self)

128
日期时间对象
• 日期时间对象方法
• 方法 datetime.timetuple() :返回日期时间结构
• 方法 datetime.utctimetuple() :返回 UTC 格式日期时间结构
• 方法 datetime.toordinal() :返回日期序数
• 方法 datetime.timestamp() :返回 POSIX 时间戳
• 方法 datetime.weekday() :返回星期信息,周一为 0 ,周日
为 6
• 方法 datetime.isowekday() :返回 ISO 星期信息,周一为
1 ,周日为 7

129
日期时间对象
• 日期时间对象方法
• 方法 datetime.isocalendar() :返回 ISO 日历三元组
• 方法 datetime.isoformat(sep = "T", timespec = "auto") :返回
ISO 日期时间字符串,格式为“ YYYY-MM-DDTHH:MM:SS”
• 方法 datetime.__str__() :返回日期时间字符串,与方法
datetime.isoformat(" ") 等价
• 方法 datetime.ctime() :返回日期时间字符串
• 方法 datetime.strftime(format) :以特定格式返回日期时间字符

• 方法 datetime.__format__(format) :与上一方法功能相同
130
日期时间对象使用示例
>>> d = datetime.datetime.today()
>>> d
datetime.datetime(2017, 3, 29, 3, 7, 19, 309101)
>>> d = datetime.datetime.utcnow()
>>> d
datetime.datetime(2017, 3, 28, 19, 7, 19, 309101)
>>> d.isoformat()
'2017-03-28T19:07:19.309101'
>>> d.strftime('%Y-%m-%d %H:%M:%S')
'2017-03-28 19:07:19'

131
日期时间对象
• 日期时间格式化
• 格式 %Y :年
• 格式 %m :月;格式 %B :月英文名;格式 %b :月英文缩

• 格式 %d :日
• 格式 %A :星期
• 格式 %H :时(二十四时制);格式 %I :时(十二时制);
格式 %p :上下午
• 格式 %M :分
• 格式 %S :秒
132
时间对象
• 时间对象构造
• 时间对象构造函数 class datetime.time(hour = 0, minute = 0,
second = 0, microsecond = 0, tzinfo = None, *fold = 0) :以给定
信息构造时间对象
• 时间类属性
• 属性 time.min :最早可表示时间 time(0, 0, 0, 0)
• 属性 time.max :最晚可表示时间 time(23, 59, 59, 999999)
• 属性 time.resolution :最小时间差值
timedelta(microseconds = 1)
133
时间对象
• 时间对象属性
• 属性 time.hour :时(二十四时制)
• 属性 time.minute :分(六十分制)
• 属性 time.second :秒(六十秒制)
• 属性 time.microsecond :微秒(百万微秒制)
• 属性 time.tzinfo :时区
• 属性 time.fold :夏时制标志

134
时间对象
• 时间对象方法
• 方法 datetime.replace(hour = self.hour, minute = self.minute,
second = self.second, microsecond = self.microsecond, tzinfo =
self.tzinfo, *fold = 0) :返回给定时间对象,可使用参数更新时
间值
• 方法 time.isoformat(timespec = "auto") :返回 ISO 时间字
符串,格式
为“ HH:MM:SS.mmmmmm” 或“ HH:MM:SS” 或“ HH:M
M:SS.mmmmmm+HH:MM” 或“ HH:MM:SS+HH:MM” ,
后两者与 UTC 时区有关
135
时间对象
• 时间对象方法
• 方法 time.utcoffset() :若 tzinfo 为 None ,返回 None ,
否则返回 self.tzinfo.utcoffset(self)
• 方法 time.dst() :若 tzinfo 为 None ,返回 None ,否则返
回 self.tzinfo.dst(self)
• 方法 time.tzname() :若 tzinfo 为 None ,返回 None ,否
则返回 self.tzinfo.tzname(self)

136
时间对象
• 时间对象方法
• 方法 time.__str__() :返回时间字符串,与方法
time.isoformat(" ") 等价
• 方法 time.strftime(format) :以特定格式返回时间字符串
• 方法 time.__format__(format) :与上一方法功能相同

137
3.6.3  随机数模块
• 随机数模块 random
• 功能:用于生成伪随机数
• 原理:梅森旋转( Mersenne Twister )算法
• 注意事项
• 随机数函数实现:内部类 Random
• 类 SystemRandom :调用操作系统函数 os.urandom() 生成
随机数
• 不能用于安全目的,安全或加密程序应使用 secrets 模块

138
随机数函数
• 簿记函数
• 函数 random.seed(a = None, version = 2) :初始化随机数生成
器,设定随机数发生器种子,可用于重复生成随机数序列
• 若 a 为 None 或无参数,使用系统当前时间作为随机数发生器种子,
否则使用整数 a
• 函数 random.getstate() :返回随机数生成器状态对象
• 函数 random.setstate(state) :设置随机数生成器状态
• 函数 random.getrandbits(k) :返回 k 随机位数的 Python
整数

139
随机数函数
• 整数函数
• 函数 random.randrange(stop) 与 random.randrange(start,
stop[, step]) :返回区间 range(start, stop, step) 中随机整数
• 函数 random.randint(a, b) :返回闭区间 [a, b] 中随机整数
• 序列函数
• 函数 random.choice(seq) :返回非空序列 seq 中随机元素
• 函数 random.shuffle(x[, random]) :将序列 x 中元素随机排
列,返回打乱后序列;有常序列使用 random.sample(x, k =
len(x))
140
随机数函数
• 序列函数
• 函数 random.sample(population, k) :从序列 population 中
随机选择 k 个元素返回
• 实值分布函数
• 函数 random.random() :返回区间 [0.0, 1.0) 中随机浮点数
• 函数 random.uniform(a, b) :返回区间 [a, b] 中随机浮点数
• 函数 random.triangular(low, high, mode) :返回区间 [low,
high] 中随机浮点数,以 mode 为中点的对称分布
• 参数 low 缺省为 0.0 , high 缺省为 1.0 , mode 缺省为区间中点

141
随机数函数
• 实值分布函数
• 函数 random.betavariate(alpha, beta) : Beta 分布
• 函数 random.expovariate(lambd) :指数分布
• 函数 random.gammavariate(alpha, beta) : Gamma 分布
• 函数 random.gauss(mu, sigma) :高斯分布
• 函数 random.lognormvariate(mu, sigma) :对数正态分布
• 函数 random.normalvariate(mu, sigma) :正态分布
• 函数 random.vonmisesvariate(mu, kappa) : Von Mises 分布
• 函数 random.paretovariate(mu, kappa) : Pareto 分布
• 函数 random.weibullvariate(mu, kappa) : Weibull 分布
142
随机数函数使用示例
>>> import random
>>> random.random()
0.8555055151474218
>>> random.uniform(21.0, 42.0)
41.96166493609364
>>> random.randrange(1, 7)
4
>>> random.randint(1, 6)
5
>>> ls = list(range(10))
>>> print(ls)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> random.shuffle(ls)
>>> print(ls)
[2, 9, 8, 1, 5, 7, 6, 4, 0, 3]

143
3.6.4  海龟作图模块
• 海龟作图:好玩的儿童编程入门知识
• 出处: Wally Feurzig 与 Seymour Papert , Logo 编程语言,
1966
• 想象:平面上有一只机器海龟,移动时绘制自身轨迹
• 起始点:原点 (0, 0) ,窗口中心
• 导入模块: import turtle
• 命令 turtle.forward(15) :前进 15 像素
• 命令 turtle.right(30) :向右(顺时针)转 30 度
• 图像绘制的全部工作由类似命令组合完成
144
3.6.4  海龟作图模块
• 基本要求: tkinter 图形库( Python 需安装 Tk 库)
• 海龟作图支持面向过程与面向对象两种方式
• 面向过程方式:简单函数调用
• 面向对象方式:定义海龟绘制窗口的图形窗口类
TurtleScreen 及其子类 Screen ;定义海龟对象的原生海龟类
RawTurtle (别名: RawPen )及其子类 Turtle (别名:
Pen )
• 两者异同:函数与类方法完全一致;面向过程方式仅有一只海
龟,单一屏幕多海龟绘图需使用面向对象方式

145
海龟作图示例:风火轮
import turtle # 导入海龟作图模块
turtle.color('red', 'yellow') # 设置画笔颜色与填充颜色
turtle.begin_fill() # 开始颜色填充
while True:
turtle.forward(400) # 前进 400 像素
turtle.left(170) # 左转 170 度
if abs(turtle.pos()) < 1: # 判断海龟是否回到原点
break
while True:
turtle.backward(400) # 后退 400 像素
turtle.right(170) # 右转 170 度
if abs(turtle.pos()) < 1:
break
turtle.end_fill() # 结束颜色填充
turtle.done() # 大功告成!
146
海龟作图示例:风火轮 147

风火轮?
曲速引擎?
RawTurtle/Turtle 方法与函数列表
• 海龟运动:移动与绘制
• 方法 turtle.forward(distance) 与 turtle.fd(distance) :保持海龟
头朝向不变,前进 distance 个单位(像素)
• 方法 turtle.backward(distance) 、 turtle.back(distance) 与
turtle.bk(distance) :保持海龟头朝向不变,后退 distance 个单
位(像素)
• 方法 turtle.right(angle) 与 turtle.rt(angle) :右转 angle 角度
• 单位缺省为度,但可设为弧度;角度方向与海龟模式有关
• 方法 turtle.left(angle) 与 turtle.lt(angle) :左转 angle 角度
• 单位缺省为度,但可设为弧度;角度方向与海龟模式有关

148
RawTurtle/Turtle 方法与相关函数列表
• 海龟运动:移动与绘制
• 方法 turtle.goto(x, y = None) 、 turtle.setpos(x, y = None) 与
turtle.setposition(x, y = None) :保持海龟头朝向不变,移动海
龟至指定位置;若画笔已按下,绘制海龟移动轨迹
• 方法 turtle.setx(x) :设置海龟 x 坐标, y 坐标不变
• 方法 turtle.setx(y) :设置海龟 y 坐标, x 坐标不变
• 方法 turtle.setheading(to_angle) 与 turtle.seth(to_angle) :
设置海龟头朝向; 0 为东, 90 为北, 180 为西, 270 为南
• 方法 turtle.home() :海龟归家(回原点),头朝向恢复初始

149
RawTurtle/Turtle 方法与相关函数列表
• 海龟运动:移动与绘制
• 方法 turtle.circle(radius, extent = None, steps = None) :以半
径 radius 画圆圆圈圈
• 未指定 extent 时画圆,指定时以当前画笔位置为端点画圆弧;半径为
正逆时针,半径为负顺时针; steps 设置多边形拟合的步数,未指定时
自动设置
• 方法 turtle.dot(size = None, *color) :画点
• size 为点直径, color 为颜色字符串或颜色( RGB 值)元组
• 方法 turtle.stamp() :在海龟当前位置留下印记(保留一份海
龟图案)
150
RawTurtle/Turtle 方法与相关函数列表
• 海龟运动:移动与绘制
• 方法 turtle.clearstamp(stampid) :清除海龟印记
• stampid 必须为 此前 turtle.stamp() 的返回值
• 方法 turtle.clearstamps(n = None) :清除海龟印记
• n 为 None 时,清除全部; n 为正时清除最初 n 个印记,为负时清
除最后 n 个印记
• 方法 turtle.undo() :取消最后一次海龟移动
• 方法 turtle.speed(speed = None) :设置海龟移动速度
• speed 为 0 至 10 之间的整数, 1 最慢, 10 很快, 0 表示无动画
(因而最快)
151
RawTurtle/Turtle 方法与相关函数列表
• 海龟运动:状态查询
• 方法 turtle.position() 与 turtle.pos() :以二维向量 Vec2D
形式返回海龟当前位置
• 方法 turtle.towards(x, y = None) :返回海龟从当前位置至指
定坐标处的角度
• 方法 turtle.xcor() :返回海龟 x 坐标
• 方法 turtle.ycor() :返回海龟 y 坐标
• 方法 turtle.heading() :返回海龟当前头朝向

152
RawTurtle/Turtle 方法与相关函数列表
• 海龟运动:状态查询
• 方法 turtle.distance(x, y = None) :返回海龟从当前位置到指
定坐标处的距离
• 海龟运动:单位设置
• 方法 turtle.degree(fullcircle = 360.0) :设置角度单位为度
• 方法 turtle.radians() :设置角度单位为弧度

153
RawTurtle/Turtle 方法与相关函数列表
• 画笔控制:绘制状态
• 方法 turtle.pendown() 、 turtle.pd() 与 turtle.down() :按下
画笔,海龟移动时绘制轨迹
• 方法 turtle.penup() 、 turtle.pu() 与 turtle.up() :抬起画笔,
移动时不绘制轨迹; width 为表示线条厚度的正整数;未指定
时,返回当前画笔厚度
• 方法 turtle.pensize(width = None) 与 turtle.width(width =
None) :设置画笔宽度并返回
• 方法 turtle.pen(pen = None, **pendict) :返回或设置画笔属性
• 方法 turtle.isdown() :
154
RawTurtle/Turtle 方法与相关函数列表
• 画笔控制:绘制状态
• 方法 turtle.pen(pen = None, **pendict) :返回或设置画笔属
性; pen 为字典, pendict 为一个以上关键字参数;画笔字
典包含如下键值对:
• shown : True/False
• Pendown : True/False
• pencolor :画笔颜色字符串或颜色元组
• fillcolor :填充颜色字符串或颜色元组
• pensize :表示画笔尺寸的正整数
• speed :海龟移动速度, 0 至 10

155
RawTurtle/Turtle 方法与相关函数列表
• 画笔控制:绘制状态
• 方法 turtle.pen(pen = None, **pendict) :返回或设置画笔属
性; pen 为字典, pendict 为一个以上关键字参数;画笔字
典包含如下键值对:
• resizemode : auto 或 user 或 moresize
• stretchfactor :正整数序偶 (a, b)
• outline :正整数
• tilt :整数
• 方法 turtle.isdown() :画笔按下时返回 True ,否则返回
False
156
RawTurtle/Turtle 方法与相关函数列表
• 画笔控制:颜色控制
• 方法 turtle.pencolor(*args) :设置画笔颜色
• pencolor() :返回当前画笔颜色字符串或元组
• pencolor(colorstring) :设置画笔颜色; colorstring 为颜色字符串,如
"red" 、 "yellow" 或 "#FF0080"
• pencolor((r, g, b)) :设置画笔颜色, (r, g, b) 为颜色元组,值区间从 0
至 colormode , colormode 值为 1.0 或 255
• pencolor(r, g, b) :设置画笔颜色,使用单独的 RGB 值

157
RawTurtle/Turtle 方法与相关函数列表
• 画笔控制:颜色控制
• 方法 turtle.fillcolor(*args) :设置填充颜色
• fillcolor() :返回当前填充颜色字符串或元组
• fillcolor(colorstring) :设置填充颜色; colorstring 为颜色字符串,如
"red" 、 "yellow" 或 "#FF0080"
• fillcolor((r, g, b)) :设置填充颜色, (r, g, b) 为颜色元组,值区间从 0
至 colormode , colormode 值为 1.0 或 255
• fillcolor(r, g, b) :设置填充颜色,使用单独的 RGB 值

158
RawTurtle/Turtle 方法与相关函数列表
• 画笔控制:颜色控制
• 方法 turtle.color(*args) :设置画笔颜色与填充颜色
• color() :返回当前画笔颜色与填充颜色字符串或元组的序偶( pair ,二
元组);画笔颜色与填充颜色由 pencolor() 与 fillcolor() 返回
• color(colorstring) 、 color((r, g, b)) 与 color(r, g, b) :设置画笔颜色与
填充颜色为相同值; colorstring 为颜色字符串,如 "red" 、
"yellow" 或 "#FF0080" , (r, g, b) 为颜色元组,值区间从 0 至
colormode , colormode 值为 1.0 或 255
• color(colorstring1, colorstring2)) 与 color((r1, g1, b1), (r2, g2, b2)) :设
置画笔颜色与填充颜色

159
RawTurtle/Turtle 方法与相关函数列表
• 画笔控制:填充
• 方法 turtle.filling() :返回填充状态,正在填充时返回
True ,否则返回 False
• 方法 turtle.begin_fill() :开始填充;准备填充前调用
• 方法 turtle.end_fill() :结束填充;填充完毕后调用
• 画笔控制:辅助绘制控制
• 方法 turtle.reset() :海龟复位,清除此前绘制图形
• 方法 turtle.clear() :清除此前绘制图形,海龟固定不动

160
RawTurtle/Turtle 方法与相关函数列表
• 画笔控制:辅助绘制控制
• 方法 turtle.write(arg, move = False, align = "left", font =
("Arial", 8, "normal")) :在海龟当前位置写字
• arg 为要输出的字符串, align 为对齐标志,取值为 "left" 、 "center"
或 "right" ; font 为字体;若 move 为 True ,海龟移动到文本右下
角,否则海龟维持不动
• 海龟状态:可见性
• 方法 turtle.hideturtle() 与 turtle.ht() :海龟躲藏
• 方法 turtle.showturtle() 与 turtle.st() :海龟露面
• 方法 turtle.isvisible() :查询海龟是否可见,隐藏为 False
161
RawTurtle/Turtle 方法与相关函数列表
• 海龟状态:外观
• 方法 turtle.shape(name = None) :设置海龟形状; name 若为
None ,返回当前形状名,预设形状有
"arrow" 、 "turtle" 、 "circle" 、 "square" 、 "triangle" 与 "classic"
• 方法 turtle.resizemode( rmode = None) :设置或返回尺寸变更模式;
rmode 取值为 "auto" 、 "user" 或 "noresize" ,为 None 时,返
回当前尺寸变更模式
• 方法 turtle.shapesize(stretch_wid = None, stretch_len = None, outline =
None) 与 turtle.turtlesize(stretch_wid = None, stretch_len = None,
outline = None) :返回或设置海龟形状尺寸;当且仅当海龟尺寸变更模
式设为 "user" 时,拉伸因子和轮廓参数才起作用

162
RawTurtle/Turtle 方法与相关函数列表
• 海龟状态:外观
• 方法 turtle.shearfactor(shear = None) :设置或返回当前剪切
角正切因子,不改变海龟头朝向
• 方法 turtle.settiltangle(angle) :海龟旋转,不改变海龟头朝向
• 在当前倾斜角基础上倾斜 angle
• 方法 turtle.tiltangle(angle) :海龟旋转,不改变海龟头朝向
• 忽略此前倾斜角,倾斜 angle
• 方法 turtle.tilt(angle = None) :海龟旋转,不改变海龟头朝向
• 设置或返回当前倾斜角;若指定 angle ,忽略此前倾斜角,倾斜该角度;
若未指定,返回海龟当前倾斜角
163
RawTurtle/Turtle 方法与相关函数列表
• 海龟状态:外观
• 方法 turtle.shapetransform(t11 = None, t12 = None, t21 =
None, t22 = None) :设置或返回当前海龟形状的变换矩阵
• 方法 turtle.get_shapepoly() :返回海龟当前形状多边形
• 事件处理
• 方法 turtle.onclick(fun, bm = 1, add = None) :束定 fun 至
海龟的鼠标单击事件
• fun 为双参数(鼠标单击点坐标)函数; bm 为鼠标按钮序数,缺省为
1 (鼠标左键); add 为 True 或 False ,前者表示添加新的束定,
后者表示删除已有的束定
164
RawTurtle/Turtle 方法与相关函数列表
• 事件处理
• 方法 turtle.onrelease(fun, bm = 1, add = None) :束定 fun
至海龟的鼠标释放事件
• fun 为双参数(鼠标单击点坐标)函数; bm 为鼠标按钮序数,缺省为
1 (鼠标左键); add 为 True 或 False ,前者表示添加新的束定,
后者表示删除已有的束定
• 方法 turtle.ondrag(fun, bm = 1, add = None) :束定 fun 至
海龟的鼠标拖动事件
• fun 为双参数(鼠标单击点坐标)函数; bm 为鼠标按钮序数,缺省为
1 (鼠标左键); add 为 True 或 False ,前者表示添加新的束定,
后者表示删除已有的束定
165
RawTurtle/Turtle 方法与相关函数列表
• 特殊海龟方法
• 方法 turtle.begin_poly() :开始记录多边形
• 方法 turtle.end_poly() :停止记录多边形顶点
• 方法 turtle.get_poly() :返回最后记录的多边形
• 方法 turtle.clone() :海龟克隆,位置、头朝向与属性不变
• 方法 turtle.getturtle() 与 turtle.getpen() :返回海龟对象本身
• 方法 turtle.getscreen() :返回屏幕对象
• 方法 turtle.setundobuffer(size) :设置或禁止撤销缓冲区
• 方法 turtle.undobufferentries() :返回撤销缓冲区中的项数
166
TurtleScren/Screen 方法与相关函数列表
• 窗口控制
• 方法 screen.bgcolor(*args) :设置或返回背景色
• args 为颜色字符串或 RGB 值,具体格式与海龟颜色设置相同
• 方法 screen.bgpic(picname = None) :设置或返回背景图片
• 方法 screen.clear() 与 screen.clearscreen() :清除绘制和全
部海龟
• 屏幕返回初始状态:白色背景,无背景图片,无事件束定,海龟轨迹动
画开关打开
• 此方法对应的全局函数为 clearscreen() ,全局函数 clear() 已用于海
龟的同名方法

167
TurtleScren/Screen 方法与相关函数列表
• 窗口控制
• 方法 screen.reset() 与 screen.resetscreen() :全部海龟复位
至初始状态
• 此方法对应的全局函数为 resetscreen() ,全局函数 reset() 已用于海龟
的同名方法
• 方法 screen.screensize(canvwidth = None, canvheight = None,
bg = None) :设置画布的尺寸与背景色
• 方法 screen.setworldcoordinates(llx, lly, urx, ury) :设置用户
自定义坐标系,并在必要时切换至 "world" 模式
• 参数为画布左下角与右上角坐标
168
TurtleScren/Screen 方法与相关函数列表
• 动画控制
• 方法 screen.delay(delay = None) :设置或返回绘制延迟,以
毫秒为单位
• 方法 screen.tracer(n = None, delay= None) :打开或关闭海龟
动画开关,设置更新图形的延迟时间
• 方法 screen.update() :屏幕更新
• 屏幕事件
• 方法 screen.listen(xdummy = None, ydummy = None) :设置
屏幕为输入焦点,以获取键盘事件
169
TurtleScren/Screen 方法与相关函数列表
• 屏幕事件
• 方法 screen.onkey(fun, key) 与 screen.onkeyrelease(fun,
key) :束定函数 fun 与按键 key 的键盘释放事件
• 方法 screen.onkeypress(fun, key = None) :指定 key 时,束
定函数 fun 与该键的键盘按下事件;否则束定函数 fun 与
所有按键的键盘按下事件
• 方法 screen.ontimer(fun, t = 0) :安装定时器,在 t 毫秒后
调用函数 fun

170
TurtleScren/Screen 方法与相关函数列表
• 屏幕事件
• 方法 screen.onclick(fun, btn = 1, add = None) 与
screen.onscreenclick(fun, btn = 1, add = None) :束定 fun 与
鼠标单击事件
• fun 为双参数函数; bm 为鼠标按钮序数,缺省为 1 (鼠标左键);
add 为 True 或 False ,前者表示添加新的束定,后者表示替换已有
的束定
• 方法 screen.mainloop() 与 screen.done() :启动事件循环
• 必须为海龟图形程序最后一条语句
• 若通过 IDLE –n 模式运行脚本,不能使用此命令

171
TurtleScren/Screen 方法与相关函数列表
• 文本与数字输入
• 方法 screen.textinput(title, prompt) :弹出对话框窗口,输入字
符串
• 方法 screen.numinput(title, prompt, default = None, minval =
None, maxval = None) :弹出对话框窗口,输入数字
• 设置与特殊方法
• 方法 screen.mode(mode = None) :设置海龟模式为 "standard"
、 "logo" 或 "world" ;若未指定,则返回当前模式
• 方法 screen.colormode(cmode = None) :指定当前颜色模式使用
实数还是整数, cmode 或者为 1.0 , 或者为 255
172
TurtleScren/Screen 方法与相关函数列表
• 设置与特殊方法
• 方法 screen.mode(mode = None) :设置海龟模式为
"standard" 、 "logo" 与 "world" ;若未指定,则返回当前
模式
• 方法 screen.colormode(cmode = None) :指定当前颜色模式
使用实数还是整数, cmode 或者为 1.0 , 或者为 255
• 方法 screen.getcanvas() :返回 TurtleScreen 的画布对象
• 方法 screen.getshapes() :返回当前可用的海龟形状名称列表
• 方法 screen.register_shape(name, shape = None) 与
screen.addshape(name, shape = None) :注册新的海龟形状
173
TurtleScren/Screen 方法与相关函数列表
• 设置与特殊方法
• 方法 screen.turtles() :返回屏幕上的海龟列表
• 方法 screen.window_height() :返回海龟窗口高度
• 方法 screen.window_width() :返回海龟窗口宽度

174
Screen 方法与相关函数列表
• 非继承自 TurtleScreen 方法
• 方法 screen.bye() :关闭海龟窗口
• 方法 screen.exitonclick() :束定 bye() 方法与屏幕的鼠标单
击事件
• 方法 screen.setup(width = _CFG["width"], height =
_CFG["height"], startx = _CFG["leftright"], starty =
_CFG["topbotom"]) :设置屏幕位置,缺省值来自配置字典
• 方法 screen.title(titlestring) :设置海龟窗口标题

175
计算机程序设计基础( Python ) 176
作 业 177
• 习题一 给定自然数 n ,编写函数,求其各位数字之和,如数 1234 各位
数字之和为 10 。编写函数,重复上述过程,直至得到 1 ~ 9 之间的某个数。
• 习题二 继续上一题。编写函数,检查 1 ~ 99999 之间所有数,给出最终
结果中 1 ~ 9 出现比例。
• 习题三 编写函数,使用递归方法求 C(n, k) 。
• 习题四 编写函数,计算圆周率。存在圆心在直角坐标系原点且半径为 1
的圆及其外切正方形。为计算方便,仅考虑位于第一象限的四分之一正方形
和四分之一圆。随机生成该四分之一正方形中一系列点,散布于四分之一圆
内比例即为圆周率四分之一。散步点越多,结果越精确,耗时也越长。

You might also like