洗礼灵魂,修炼python(21)--自定义函数(2)—函数文档,doctest模块,形参,实参,默认参数,关键字参数,收集参数,位置参数
函数文档
1.什么是函数文档:
就是放在函数体之前的一段说明,其本身是一段字符串,一个完整的函数需要带有函数文档,这样利于他人阅读,方便理解此函数的作用,能做什么运算
2.怎么查看函数文档:
function.__doc__
注意:不加小括号
3.例:
你可能会想,假如我不传入参数能直接打印函数文档吗?
测试一下就知道:
结果是可以的
接着想,前面说不能带小括号,我确认一下是不是真的不能带小括号呢:
果然是不行的,接着看:
有没有什么发现?总结一下:
函数的.__doc__属性里,因为函数加括号表示实例化函数,即对函数的调用,不加括号才是对函数自身的引用,但是函数文档.__doc__是属性,不是方法,不能加括号
那为什么一定要加双下划线?
因为它是魔法方法,系统属性都是用双下划线,并且大部分魔法方法都是系统属性
你应该会想,这,函数文档完全没有参与计算啊,那我留它干嘛?不是说python的宗旨是优雅而精简,我不要它啊,是的,道理是这么个道理,你确实是不需要留它,有没有它确实计算不受影响,这里暂且不说,请看下面的。
还有个方法可以访问函数文档:使用help函数
是不是有点突然的恍然大悟,哎呀,我靠,这函数文档不就是帮助文档吗?用来说明函数的方法 ,怎么使用的,方便他人读懂代码读懂函数用法的,是啊,函数文档就是这个作用,那么你现在还觉得函数文档是没用的吗?函数文档虽然看起来不参与运算处理,但是作用真的很大,一个合格的程序员在自定义函数时都会加上函数文档
那么既然函数文档这么重要,那是不是函数文档就真的无法进行运算,当然是可以的,不过它的作用比运算更强大,是作测试用,主角登场:测试框架:doctest模块
doctest
1.作用:
允许在文档字符串内嵌入注释以显示各种语句的用法或者叫期望行为,尤其是函数和方法的结果。
2.创建可自测试的模块:
在模块的尾部添加如下代码:
if __name__=='__main__': import doctest doctest.testmod(verbose=True)
这样模块在python中直接运行时即能进行自我测试
例:
结果:
如果还是不太有感觉,自己测试,给你代码:
# -*- coding:utf-8 -*- def my1(num1,num2): ''' >>> my1(3,7) 21 >>> my1('py',4) 'pypypypy' ''' return num1*num2 if __name__=='__main__': import doctest doctest.testmod(verbose=True)
有几点需要注意:
1):必须要加入‘>>>’,这样在其自动测试时才会执行测试,在python的官方文档中,对doctest是这样介绍的:doctest模块会搜索那些看起来像是python交互式会话中的代码片段,然后尝试执行并验证结果,就印证这个效果。
2):'>>>' 开头的行就是doctest测试用例。不带 '>>>' 的行就是测试用例的输出。如果实际运行的结果与期望的结果不一致,就标记为测试失败。
3):doctest.testmod方法里有个verbose参数,如果设置为True则在执行测试的时候会输出详细信息。默认是False,表示运行测试时,只有失败的用例会输出详细信息,成功的测试用例不会输入任何信息
4):有两个地方可以放doctest模块,一个位置是模块的最开头,另一个位置是函数声明语句的下一行(就像上面的例子这样)。除此之外的其它地方不能放,放了也不会执行
如果__main__函数有其他用途,不方便调用doctest.testmod()方法,那么可以用另外一种执行测试的方法:
python -m doctest (模块名).py或者 python -m doctest -v (模块名).py。这里 -m 表示引用一个模块,-v 等价于 verbose=True。运行输出与上面基本一样
如果不想将doctest嵌入到python的源码中,则可以建立一个独立的文本文件来保存测试模块。将doctest从上面的python源码中剥离出来放到一个单独的文件里
例:
文件代码和存放位置
同一路径下,存放有内容如下的txt文档:
使用命令:
python -m doctest -v doct.txt () #-m 表示引用一个模块,-v 等价于 verbose=True
结果:
发现结果是一样的
不过要注意的是,在Windows下运行,注意编码问题,尽量不要使用中文。没办法,这个问题一直存在
参数:
一.实参指函数调用过程中传递进入的参数,叫做“实际参数”,或者简称“实参”
例:def My1(‘yang’):此时括号里面的即为实参,及这个‘yang’参数是一个实际的参数,在创建函数时已经定义好,后面也无法更改
二.形参指创建函数时小括号里面定义的参数,叫做“形式参数”,或者简称“形参”
例:def my1(name):此时里面的name即为形参,即这个name只是一个形式,当实际调用时可以任意一个参数
1.关键字参数:关键字参数调用时是再赋值,其实也就是形参,不过这是完全不同的概念
例:def my2(name,words):其中name,words则为关键字参数,但是调用时则必须赋值,不然报错
2.默认参数:就是在函数定义时为形参附一个初始值,防止调用时忘记赋值,程序出错。如果在调用函数时,没有给参数也不会报错,当前就是默认值,如果调用时给定参数,此时的值就是给定的参数值
例:def my2(name="I",words="U"):其中name="I"或者words="U" 整个则是默认参数
3.收集参数:可以赋值多个,就像一个无底洞,你给我多少,我都接住,来者不拒
例:def test(*params):形参前加*,表示收集参数
有没有发现,打印出来是元组?所以,收集参数得到的是元组
注意:
1):参数之间必须用逗号隔开,不然报错
2):在定义收集参数后,调用收集参数时,直接给参数名,不要再在前面加符号【*】
3):收集参数后面如果还有形参,此时最好把后面的形参定义为默认参数,不然报错:
因为前面的参数都被收集参数拿去了,所以后面个参数永远都获不到值,所以报错。
而这是python3的代码在python2里,在创建的时候就已经不被允许了:
定义默认参数之后:
同样的python2里即使给了默认参数还是无法创建
4.位置参数:任意位置参数
例:def test(m,*y,**z):形参前加**,表示位置参数,**z则是位置参数
发现打印出来的是字典?所以,位置参数得到的就是字典
位置参数和收集参数的区别:
再一例:
所以,不管是什么类型的参数,都必须匹配
总结:
1.所有参数都必须有匹配的值才行
2.参数位置:
- 先是位置匹配的参数
- 再是关键字匹配的参数
- 手机匹配的元组参数
- 手机匹配的关键字参数
3.以上几类参数不能同时存在:
(左边python2,右边python3)
参数就介绍完了,记住一句话:调用是为了分解,定义为了整合