python学习笔记(六)抽象(函数)
个人笔记,仅供参考
六、抽象(函数)
在大型项目中,经常有一些功能要重复使用,为了编程的效率,不可能每使用一次就要写一次相关代码。而应该把这些代码写成函数,使用时调用即可。
1、自定义函数
使用def来定义函数
def hello(name):
return 'Hello, ' + name + '!'
运行这些代码后可以生成一个名为hello的新函数,它返回一个字符串,其中包含向唯一参数指定的人发出问候语。
生成斐波那契数列的函数:
def fibs(num):
result = [0,1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
调用时传递需要生成的数的个数即可
1.1、给函数写文档
有的时候我们拿到一个函数却并不知道怎么用,这就需要在写函数的时候加上文档注释说明用法,不会用的时候查看就好。
def fibs(num):
'传递要生成数列的长度'
result = [0,1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
如第二行就是文档字符串,如果要多行可以用三个引号。
可以使用如下方法查文档字符串:fibs._doc_
。
2、参数
不用担心参数的值,编写函数时只要使用参数名称就可以了
参数的本质是变量,在函数内对参数赋值对外部没有影响
2.1、关键字参数和默认值
在调用时使用名称指定的参数称为关键字参数,主要优点是让你不用记各个参数的位置,只用记有哪些参数即可,调用方法如下
fibs(10)
fibs(num=10)
这两种调用方法看起来区别不大,但是在参数很多是关键字参数会很有用
在定义函数的时候可以给变量设置默认值,这样在调用时如果没有指定这个参数,就将按默认值执行,而不是报错。
def fibs(num=10):
'传递要生成数列的长度'
result = [0,1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
第一行给num指定了默认值10
2.2、收集参数
收集参数可以让用户调用是输入多个参数,函数将多余的参数收集并存在元组中。
def print_param(title,*params):
print(title)
print(params)
如以上函数,第一个参数将被传递,而 * 后的参数将被收集并存在元组中。调用如下
print_param('params',1,2,3)
结果如下:
params
(1, 2, 3)
如果要在其他位置设置收集参数,那么在调用时后面的参数就要用关键字参数
2.3、分配参数
与收集参数相反,在调用时使用星号并传递一个元组,将会把元组的值分别传递给各个参数。
3、作用域
变量到底是什么?可以将其视为指向值的名称。因此,执行赋值语句x = 1后,名称x指向值1,这几乎与使用字典时一样,只是你使用的字典“看不见”。其实有一个名为vars的内置函数,它返回这个不可见的字典。
>>> x = 1
>>> scope = vars()
>>> scope['x']
1
>>> scope['x'] += 1
>>> x
2
这个看不见的字典称为命名空间或作用域,除全局作用域外,每个函数调用都将创建一个。
>>> def foo(): x = 42
...
>>> x = 1
>>> foo()
>>> x
1
在这里,函数foo创建了变量x,但当你最终查看时,它却没变。这是因为在调用foo是创建了新的命名空间,供foo中的代码块使用。赋值语句x = 42是在这个内部作用域中执行的,不影响外部作用域的x。
如果要在函数中访问全局变量要注意变量的名称没有重复(这样访问容易出bug)
重名时要访问全局变量可以使用glbal指定是全局变量,例如global x
指定全局变量x
4、递归
函数调用自己被称为递归,下面是一个递归函数定义:
def recursion():
return recursion()
这个函数会不断调用自身,最后崩溃。这样的递归被称为无穷递归,因为它从理论上来说永远不会停止。
真正的递归函数要包括以下两部分:
基线条件:满足这种条件时函数将直接返回一个值
递归条件:包含一个或多个调用,这些调用旨在解决问题的一部分