作业
1、怎么给函数编写⽂档?
在函数内部加注释
2、怎么给函数参数和返回值注解?
加注释
3、闭包中,怎么对数字、字符串、元组等不可变元素更新。
需要 nonlocal 关键字去声明,然后修改
但是如果是列表,字典这样的就可以不用,直接用索引修改。
这里关于函数接收参数和形参实参以及全局变量局部变量还想说一下自己的理解和体会:
首先是对于形参和实参的理解:
1.函数的输入参数实际上都是输入它们的内存地址,而不是具体的数值。
2. 在函数里,是一个形参接收的输入实参所指向的内存地址。针对地址不可变的变量,如果对形参进行了修改,形参会指向一个新的内存地址。因此这对实参指向的地址没有任何影响。
4. 但如果是地址可变的变量,形参接受了这个地址以后,形参针对这个地址内部元素的操作就会修改原来的这个实参。
5. 这个就好像是 a=[1,2,3]
,
形参就相当于 b=a
形参和实参指向地址是相同的
形参修改b[0]=10
,对应的地址内容会修改,但是地址不变,实参因为指向的地址不变,因此也会被修改。
对于全局变量和局部变量来说:
1. 在函数外面定义的变量叫全局变量,在整个程序中都有效,函数中可以直接引用它。
2. 函数在引用全局变量的时候也是引用的地址,不是具体数值。
3. 但是,对于地址不可变的全局变量,由于函数是把外面的全局变量的地址给传递进去,
在函数里面改了数值相当于把地址指向了另外一个,但是新地址并不知道是什么变量去指向它的。因此在函数中不能更改,改的话会报错。
4.对于地址可变的全局变量,改变数值并不会改变地址,全局变量还是指向原地址,但是里面的内容更改了,所以可以在函数中更改。那么对于地址不可变的全局变量的话,怎么在函数中修改它的值呢,可以在函数中进行声明global 变量
程序实验结果如下:
num1 = 100
def cal1():
num1 += 2
print(num1)
cal1()#UnboundLocalError: local variable 'num1' referenced before assignment
num2 = [100,100]
def cal2():
num2[0] += 2
print(num2)
cal2()#[102, 100]
num3 = 100
def cal3():
global num3
num3 += 2
print(num3)
cal3()#102
4、分别根据每一行的首元素和尾元素大小对二维列表 a = [[6, 5], [3, 7], [2, 8]] 排序。(利用lambda表达式)
a = [[6, 5], [3, 7], [2, 8]]
# 按首元素排序
sorted(a, key = lambda x: x[0])
# 按尾元素排序
sorted(a, key = lambda x: x[1])
5、利用python解决汉诺塔问题?
def HanNuoTa(n, a = 'a', b='b', c = 'c'):
if n == 1:
print('从', a, '移到', c)
else:
HanNuoTa(n-1, a, c, b)
print('从', a, '移到', c)
HanNuoTa(n-1, b, a, c)
>>> HanNuoTa(3)
从 a 移到 c
从 a 移到 b
从 c 移到 b
从 a 移到 c
从 b 移到 a
从 b 移到 c
从 a 移到 c
1 函数
1.1 函数基本结构
一个函数的定义主要有三部分:
函数名、输入、输出
def function(input):
#需要执行的代码
return output
注意:函数名不能跟python的保留字重复
1.2 函数的输入
函数的输入主要有两种情况:
1、定义几个参数,调用的时候就输入几个参数
2、定义若干个参数,根据我输入的参数个数和类型执行不同的功能
1.2.1
第一种情况很好理解,我怎么定义就怎么调用。例如
def function(a,b):
return a+b
function(1,2) #3
这里还有一种情况是默认参数。
def funtion(a,b=2):
return a+b
function(1) #3
这里我用 b=2 规定了函数参数的默认值,这样我可以不传入b这个参数,默认为2。
1.2.2
至于第二种情况,就是可变输入
def function(a,b=2, *args):
return a+b
可变参数就是传入的参数个数是可变的,可以是 0, 1, 2 到任意个,是不定长的参数。
如果定义函数的时候有*args, 表示这里会把接收到的变量放在一起,打包为一个元组,存储在args这个形参中去。
调用数据的方法也很简单,就是从args这个元组变量中取值,方法与一般的元组方法一致。
例如:
def function(a,b=2, *args):
return a + b + sum(list(args))
function(1,2,3,4) # 10
此外,这个可变输入还有一种功能是可以接收关键字参数。写法为:
def function(a,b=2, *args, **kwargs):
print(kwargs)
return a + b + sum(list(args))
>>> function(1,2,3,4, c=10)
{'c': 10}
10
从上面的例子可以看到,这里是可以接收一个类似于表达式的东西c=10,但是这个东西被打包成了一个字典键值对的形式传给了kwargs。
字典因为它是用键来索引,所以在一些场景下,或者是团队在编写的时候容易统一规范,方便读取数据,了解数据的含义。因此用可变输入的形式来输入,是对函数输入的拓展。
**注意:需要区别的是
*args是接收所有类型的数据参数的,包括数字,字符串,列表,元组,字典,集合等等。接收了多少就全部打包多少,打包后的arg里就有多少元素。
**kwargs 则是接收表达式形式的参数,打包成一个字典。
也就是说,一个字典输入进来,是不会被kwargs接受的,它会变成args元组的一个元素 **
例如:
def function(a, *args, **kwargs):
print(a)
print(args)
print(kwargs)
pass
>>> function(1, 2,{'a':10},(10,23), [12,2,5], b = 'python', c = 'matlab')
1
(2, {'a': 10}, (10, 23), [12, 2, 5])
{'b': 'python', 'c': 'matlab'}
1.3 函数的输出
1.3.1 函数有输出
函数的输出是用一个return来表示的。return几个参数,就输出几个参数。python是支持多个输出的。例如
def function(a, b):
return [a+b, a*b]
>>> [c, d] = function(1,2)
>>> c
3
>>> d
2
当需要输出多个参数的时候,可以用一个列表[ ],或者元组 () 去括起来,在调用的时候再用同样的一个列表或者元组去接收它。
当然,也有一种偷懒的办法,就是不用括起来,例如
def function(a, b):
return a+b, a*b
>>> c, d = function(1,2)
>>> c
3
>>> d
2
这样也是可以的,为什么呢?
在这样的情况下,python会默认把输出的多个参数一起打包成一个元组。接收输出参数的时候也是对应的接收。就是这么神奇
特别要注意的是:
函数运行到return, 就结束了!!!就会跳出这个函数!!!
所以如果你的函数里有条件判断嵌套多个return的时候,一定要注意!
1.3.2 函数没有输出
当然函数的本质其实是组合一段功能重复的代码块,所以重点是执行的内容,至于是不是要有输出,就不一定了。
函数完全可以没有输出。但是也可以实现功能。比如之前在编写将成绩改成数字的作业中,函数就没有定义输出return。
1.4 递归函数
递归函数就是一个函数里面调用了它自己。
用一个小程序来帮助理解,下面是用递归函数的方法来计算阶乘。
def test(num):
if num>1:
return num*test(num-1)
else:
return 1
当num=3时,函数的运行顺序为
num = 3
def test(3):
if num>1:
return 3*test(3-1)
else:
return 1
再调用test(2)
def test(2):
if num>1:
return 2*test(2-1)
else:
return 1
再调用test(1)
def test(1):
return 1
此时函数结束调用再往前返回值。
注意:调用函数时,为了保存这个函数中的数据,需要对其保存数据,即每调用以此函数(不管时自己还是其他函数),都要向内存中保存一些数据,因此一个程序不能永无休止的调用函数,因为每调用一次就要保存数据,而内存的大小时有限的,保存数据的过程是一个先进后出的过程,也就是’入栈’。
上面的函数,在num= 3的时候,在一个内存中回会存进去3这个形参,再调用继续在里面存2,再调用再存,一致直等内存存不满,存完了后,后面的存入的先出来用,因此是先进后出,栈的形式。
2 匿名函数lambda
匿名函数的格式是这样的:
lambda x: x**2
lambda后面接函数的输入,冒号后面接函数的输出。
这个适用于编写特别简单又需要多次重复使用的时候。
y = lambda x: x**2
[y(i) for i in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
调用方式是
f = lambda x: x**2
>>> f(10)
100
后面感觉lambda函数用的最实用的地方还是在表格这样作为排序的条件来使用。单纯的lambda计算的功能好像并不是很实用。
还可以用在列表推导式:
>>> y = lambda x: x**2
>>> [y(i) for i in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]