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的标准输入函数,从键盘读入内容,返回字符串形式;因此输入数字的时候通常需要转换函数

练习:

  1. 利用math库,完成is_square(n)函数的定义,判断n是否为完全平方数。
  2. 定义函数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库的使用
posted @ 2020-11-17 10:49  hzy&hmcj  阅读(234)  评论(0)    收藏  举报