《Think Python 2e》学习精粹(三): 函数

《Think Python 2e》学习精粹(三): 函数



  • 函数(function) :一个有命名的、执行某个计算的语句序列(sequence of statements);

1、函数调用

  • 函数调用(function call) 方式:函数名(表达式);
  • 调用函数时括号里的表达式称为实参(argument)
  • 函数“接受”(accept)实参(有的话)后返回(return)得到一个结果即返回值(return value);
>>> type('Hello, World!')
<class 'str'>
  • Python提供了能够将值从一种类型转换为另一种类型的内建函数;
    • 函数 int 接受任意值,并在其能做到的情况下,将该值转换成一个整型数;
    • 函数 float 可以将整型数和字符串转换为浮点数;
    • 函数 str 可以将其实参转换成字符串;
>>> int(32.98)
32
>>> int('32')
32
>>> int('32.98')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '32.98'
>>> float(32)
32.0
>>> float('32.98')
32.98
>>> str(32.98)
'32.98'

2、数学函数

  • 模块(module):一个含有相关函数的文件;
  • 数学模块(math) 提供了大部分常用的数学函数和变量;
  • 在使用模块之前,需要通过 导入语句(import statement) 导入该模块;
  • 导入语句生成一个模块对象(module object),在未导入时未生成模块对象;
>>> math
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'math' is not defined
>>> import math
>>> math
<module 'math' (built-in)>
  • 模块对象包括了定义在模块内的所有函数和变量;
  • 模块对象中的函数或者变量命名:模块的名字与函数名(变量名)组合而成, 并以点号分隔开来, 这种命名形式被称作点标记法(dot notation)
>>> import math
>>> math.pi
3.141592653589793
>>> math.sqrt(2)
1.4142135623730951

3、组合

  • 编程语言的最有用特征之一,是能够将小块构建材料(building blocks)组合(compose) 在一起;
  • 值可以是一个任意类型的表达式;
  • 例外: 赋值语句的左侧必须是一个变量名;
>>> hours = 2
>>> minutes = hours * 60                 # 正确
>>> hours * 60 = minutes                 # 错误!
  File "<stdin>", line 1
SyntaxError: cannot assign to operator

4、新建函数

  • 函数定义(function definition) :指定新函数的名称、当函数被调用时执行的语句序列;
  • def 是表明从此行开始是函数定义的关键字;
  • 函数名与变量名具有同样的规则;
  • 函数名后面的括号中是实参(有的话),实参不止一个的话用逗号分隔;
  • 函数定义的构成规定:
    • 函数定义的第一行被称作函数头(header), 其余部分被称作函数体(body)
    • 函数头必须以冒号结尾,而函数体必须缩进(惯例四个空格);
    • 函数体能包含任意条语句,但必须以空行结束;
  • 新建函数调用与内建函数调用一致,包括被应用在另一个函数的内部;
def print_gsf():
	print('I am healthy.')
	print('And I am happy.')
	
def print_twice():
	print_gsf()
	print_gsf()
	
print_twice()
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\print_twice.py
I am healthy.
And I am happy.
I am healthy.
And I am happy.

5、定义和使用

  • 函数定义被执行后,创建函数对象;
  • 函数定义内部的语句在函数被调用之前不会执行、不会产生输出;
  • 函数定义必须在其第一次被调用之前执行,未定义先调用会报错,例如:NameError: name 'print_twice' is not defined
print_twice()
def print_gsf():
	print('I am healthy.')
	print('And I am happy.')
	
def print_twice():
	print_gsf()
	print_gsf()
	
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\print_twice_1.py
Traceback (most recent call last):
  File "D:\WorkSpace\thinkpython2e\print_twice_1.py", line 1, in <module>
    print_twice()
NameError: name 'print_twice' is not defined

6、执行流程

  • 执行流程(flow of execution): 语句执行的顺序;
  • 执行流程总是从程序的第一条语句开始,自顶向下,每次执行一条语句;
  • 函数定义不改变程序执行的流程,函数不被调用时内部的语句不会执行;
  • 函数调用,执行流程不进入下一条语句,而是跳入函数体,开始执行函数定义里的语句,然后再回到它离开的位置;

7、形参和实参

  • 实参 :调用函数时,(有时候)需要输入参数,输入的一个或者几个参数称为实参;
  • 在函数调用时,实参被赋给函数定义时确定的函数形参(parameters)
  • 组合规则适用于内建函数和自定义函数(programmer-defined functions)的实参;
  • 在函数被调用之前,实参会先进行计算再赋给形参;
def print_gsf(years_old):
	print(years_old)
	
def print_twice():
	print_gsf(2020-1968)
	print_gsf("I'm so young!")
	
print_twice()
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\print_yeas_old.py
52
I'm so young!

8、变量和形参都是局部的

  • 函数定义时创建的变量是局部的(local) , 只在函数内部存在;
  • 当函数调用结束时,变量被销毁,在函数外这个变量是未定义的;

9、堆栈图

  • 堆栈图(stack diagram) : 用以说明每个变量的值、每个变量所属的函数并跟踪哪个变量能在哪儿用的图形;
    在这里插入图片描述
  • 每个函数用一个栈帧(frame) 表示;
  • 一个栈帧就是一个线框,函数名在旁边,形参以及函数内部的变量则在里面;
  • 栈帧排列成栈的形式,说明了哪个函数调用了哪个函数等信息;
  • __main__是一个表示最上层栈帧的特殊名字;
  • 如果函数调用时发生错误,Python会打印出错函数的名字以及调用它的函数的名字, 以及调用后面这个函数的函数的名字,一直追溯到__main__为止,这个函数列表被称作回溯(traceback)
  • 回溯中的函数顺序,与堆栈图中的函数顺序一致,出错时正在运行的那个函数则位于回溯信息的底部;

10、有返回值函数和无返回值函数

  • 有返回值函数(fruitful functions):会返回结果的函数;
  • 无返回值函数(void functions):执行一个动作但是不返回任何值的函数;
  • 在交互模式下调用一个函数时,Python解释器会马上显示结果;
  • 在脚本中,单单调用一个有返回值函数, 返回值就永远丢失;
  • 将无返回值函数的结果赋给一个变量:
    • 会得到特殊值 None ;
    • None 是一个自己有独立类型的特殊值;
>>> print(type(None))
<class 'NoneType'>

11、为什么写函数?

  • 给一组语句命名;
  • 消除重复的代码;
  • 分解长程序;
  • 重复使用;

12、调试

  • 调试,是最重要的技能之一;
  • 调试像是侦探工作:面对一些线索,推理出导致结果的进程(processes)和事件(events);
  • 调试也像是一门实验科学:猜测出错的地方,修改程序,再试一次,直至程序正常运行 ;
  • 在某种意义上,编程和调试是同一件事,编程是逐步调试一个程序,直到出现期待结果的过程;
  • 应该从一个能正常运行(working) 的程序开始,每次只做一些小改动,并同步进行调试。

猜你喜欢

转载自blog.csdn.net/weixin_41217917/article/details/110633088
今日推荐