函数很重要 函数很重要 函数很重要
看了这个前提就知道这节课有多关键,开始。
-
定义函数
for example
输出斐波那契序列
def feibo(n):
'''输出斐波那契数列
输出n个数
'''
a,b = 0, 1
list = []
while len(list) < n:
a,b = b, a+b
list.append(b)
print(*list)
feibo(10)
输出结果:
1 2 3 5 8 13 21 34 55 89
第一行:def,命名规范,参数,格式
关键字 def 引入了一个函数 定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开始,必须是缩进的。注意':'。
这里我命名为 feibo,参数为 n 。
第二行:文档字符串
第一行应该是关于对象用途的简介。简短起见,不用明确的陈述对象名或类型,因为它们可以从别的途径了解到(除非这个名字碰巧就是描述这个函数操作的动词)。这一行应该以大写字母开头,以句号结尾。
>>> def my_function():
... """Do nothing, but document it.
...
... No, really, it doesn't do anything
... """
... pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.
No, really, it doesn't do anything.
函数 调用 会为函数局部变量生成一个新的符号表。确切的说,所有函数中的变量赋值都是将值存储在局部符号表。
变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表。因此,全局变量不能在函数中直接赋值(除非用 [global]语句命名),尽管他们可以被引用。
函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是 传值调用 (这里的 值 总是一个对象 引用 ,而不是该对象的值)。 一个函数被另一个函数调用时,一个新的局部符号表在调用过程中被创建。
一个函数定义会在当前符号表内引入函数名。函数名指代的值(即函数体)有一个被 Python 解释器认定为 用户自定义函数 的类型。 这个值可以赋予其他的名字(即变量名),然后它也可以被当做函数使用。这可以作为通用的重命名机制。
f = feibo
f(20)
输出结果:
1 2 3 5 8 13 21 34 55 89
1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946
>>>
没有 return 语句的函数确实会返回一个值,虽然是一个相当令人厌烦的值(指 None )。这个值被称为 None(这是一个内建名称)。如果 None 值是唯一被书写的值,那么在写的时候通常会被解释器忽略(即不输出任何内容)。
-
默认参数值
最常用的一种形式是为一个或多个参数指定默认值。
默认值在函数 定义 作用域被解析
i = 5
def f(x = i):
print(x)
i = 6
f()
输出结果:
5
=====
i = 5
def f(x = i):
#加了一行代码
x = i
print(x)
i = 6
f()
输出结果:
6
默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
输出结果:
[1]
[1, 2]
[1, 2, 3]
-
关键字参数值
在函数调用中,关键字的参数必须跟随在位置参数的后面。传递的所有关键字参数必须与函数接受的某个参数相匹配 (例如 actor不是 parrot函数的有效参数),它们的顺序并不重要。这也包括非可选参数(例如 parrot(voltage=1000)也是有效的)。任何参数都不可以多次赋值。
主要看有没有默认值,没有默认值的参数是不是被赋值了
dic = {'shi':'a','hu':'b','li':'c','liu':'d'}
def ranking(name: str = 's',age: str = 'A'):
print('%s的age是%s'%(name,age))
return
for i,j in enumerate(dic):
ranking(j,dic[j])
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
-
可变参数列表
一个最不常用的选择是可以让函数调用可变个数的参数。这些参数被包装进一个元组。在这些可变个数的参数之前,可以有零到多个普通的参数。
通常,这些可变参数是参数列表中的最后一个,因为它们将把所有的剩余输入参数传递给函数。任何出现在 *args后的参数是关键字参数,这意味着,他们只能被用作关键字,而不是位置参数。
-
参数列表的分拆
另有一种相反的情况: 当你要传递的参数已经是一个列表,但要调用的函数却接受分开一个个的参数值。这时候你要把已有的列表拆开来。
你可以在调用函数时加一个 * 操作符来自动把参数列表拆开。
>>> print(list)
(1, 3, 4, 5, 6)
>>> print(*list)
1 3 4 5 6
>>> print(range(1,5))
range(1, 5)
>>> print(*range(1,5))
1 2 3 4
用 ** 操作符分拆关键字参数为字典。
-
函数注解
函数注解是关于用户自定义的函数的完全可选的、随意的元数据信息。
注解是以字典形式存储在函数的 annotations 属性中,对函数的其它部分没有任何影响。
参数注解(Parameter annotations)是定义在参数名称的冒号后面,紧随着一个用来表示注解的值得表达式。返回注释(Return annotations)是定义在一个 -> 后面,紧随着一个表达式,在冒号与 -> 之间。
def introDog(name: str = 'dog',age: int = 2, size: '大小' = 'big') -> list:
print(name,age,size)
return [str,age,size]
introDog('小白',22,'small')
print(introDog.__annotations__)
输出结果:
小白 22 small
{'size': '大小', 'name': <class 'str'>, 'age': <class 'int'>, 'return': <class 'list'>}
-
遗留问题
1.作用域问题
2.函数的参数
3.编码风格