Python基础讲义(三):函数初步
函数初步
0x01内容导图

0x02函数定义
-
程序的本质:问题分解,逐步求精
-
基本原则:一个函数一个功能
-
函数定义语法:
def fun_name([args]): statements [return values] -
函数名要有意义,提高可读性;
- args:参数列表,相当于函数的输入,定义时称为形式参数;可以没有参数
- return values:返回值,相当于函数的输出(可以有多个返回值);可以没有返回值
-
函数调用语法:function_name(args),圆括号不能省略;调用时,参数被称为实际参数
代码示例(文件方式,is_leap.py):判断是否为闰年
#请熟练掌握下述框架,养成自顶向下的编码习惯
def is_leap(year):
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
def run():
year = int(input("please input a year:")) #输入
flag = is_leap(year) #处理
print(f"{year}年是闰年:{flag}") #输出
if __name__ == "__main__": #是否为主模块:直接运行该模块,则为主;其他方式,如被导入,则不是
run()
说明:
- Python中语句块以缩进表示归属,函数是语句块,函数体必须缩进
- input函数是Python的标准输入函数,从键盘读入内容,返回字符串形式;因此输入数字的时候通常需要转换函数
练习:
- 利用math库,完成is_square(n)函数的定义,判断n是否为完全平方数。
- 定义函数calc_area(w, h):计算长方形面积并返回
0x03变量作用范围
-
定义在函数内的称为局部变量,只能在函数内访问
-
定义在函数外的称为全局变量,尽量少用
- 函数内可读访问全局变量
- 写访问,需要使用global语句声明
- 同名解析:就近原则
-
locals()/globals()函数:局部/全局命名空间
-
查看函数:
- dir函数:显示模块中定义的函数
- help函数:显示函数的用法
代码示例(文件方式,scope.py):
#========================测试一============================
def disp():
name = "world"
print("hello" + name)
print(name) #error,局部变量,外面不能访问
#========================测试二============================
#函数内可以读访问全局变量
def test():
return x + y
x, y = 2, 3
test()
#========================测试三============================
def method():
x = 10 #赋值即定义,此处x为局部变量
print(x) #就近原则,x为局部变量
x = 5 #此处x为全局变量
method()
print(x) #打印全局变量x,其值仍为5
#========================测试四============================
def test2():
#global x
x += 1 #报错,局部变量未赋值就使用
print(x)
x = 5
test2()
print(x)
"""错误解析:展开x = x + 1,Python从左开始解析,第1次遇到x,由于出现在赋值号左边,x被解释为局部变量(赋值即定义);继续解析遇到第2个x,就近原则访问局部变量x,而这时x还未完成赋值,因此报错。"""
#修改办法:第16行取消注释,将x声明为全局,然后才能修改x的值
0x04测试驱动开发
-
测试先行,结对编码
- 对外接口设计:先思考函数怎么用,会返回什么结果,即测试用例设计
- 代码实现:让测试通过
-
Python自带测试库:doctest
- 嵌入式:利用文档注释(三引号注释)
代码示例(闰年判断为例):
def is_leap(year): """ 判断year是否为闰年,用法如下: >>> is_leap(2000) True >>> is_leap(1998) False >>> is_leap(1900) False >>> is_leap(2020) True """ return year % 4 == 0 #故意实现错误 if __name__ == "__main__": import doctest doctest.testmod(verbose=True)
测试部分结果如下:
...
Failed example:
is_leap(1900)
Expected:
False
Got:
True
Trying:
is_leap(2020)
Expecting:
True
ok
1 items had failures:
1 of 4 in __main__.is_leap
4 tests in 2 items.
3 passed and 1 failed.
***Test Failed*** 1 failures.
上述结果显示,我们的3个测试都通过了,但1900年测试失败,不是闰年却返回了是,代码实现应该和前面的例子相同,修改后再测试可以看到:
1 items passed all tests:
4 tests in __main__.is_leap
4 tests in 2 items.
4 passed and 0 failed.
Test passed.
- 独立式:测试用例单独用txt文件保存,代码和用例分开(保存在同一目录下)
代码示例(一元二次方程求解),测试文件solve_equation_test_cases.txt如下:
>>> from solve_equation import *
>>> solve_equation(1, -2, 1)
(1.0, 1.0)
>>> solve_equation(1, 1, -6)
(2.0, -3.0)
>>> solve_equation(2, -1, -3)
(1.5, -1.0)
代码文件solve_equation.py如下:
def solve_equation(a, b, c):
import math
delta = b*b - 4*a*c
delta = math.sqrt(delta)
x1 = (-b + delta) / (2*a)
x2 = (-b - delta) / (2*a)
return x1, x2
运行方式:命令行下,切换到对应目录,然后运行命令python -m doctest -v solve_equation_test_cases.txt,其运行结果如下:
Trying:
from solve_equation import *
Expecting nothing
ok
Trying:
solve_equation(1, -2, 1)
Expecting:
(1.0, 1.0)
ok
Trying:
solve_equation(1, 1, -6)
Expecting:
(2.0, -3.0)
ok
Trying:
solve_equation(2, -1, -3)
Expecting:
(1.5, -1.0)
ok
1 items passed all tests:
4 tests in solve_equation_test_cases.txt
4 tests in 1 items.
4 passed and 0 failed.
Test passed.
综上,不管是嵌入式还是独立式,使用doctest进行测试驱动开发,明显的一个好处就是测试用例可以存储,可以反复进行测试,特别是我们修改代码的时候,可以保证之前通过的测试必须再通过。
0x05小结
- 理解模块化思想,熟练掌握函数定义语法
- 掌握变量的作用范围
- 理解测试驱动开发,掌握doctest库的使用
浙公网安备 33010602011771号