一木.溪桥 在Logic Education跟Amy学Python
12期:Python基础课 一木.溪桥学Python-09:函数的返回值、作用域、作用域的优先级、递归函数、内置文件中常用方法、匿名函数lambda、高阶函数
日期:2021年1月4日
学习目标:
- 函数的返回值
- 函数的作用域
- 作用域的优先级
- 递归函数
- 内置文件中常用方法
- 匿名函数lambda
- 高阶函数
学习内容:
函数的返回值
-
当两个函数之间,想要互相使用到内部变量时,就可以应用到函数的返回值。
-
函数的返回值定义:
-
tips
使用 return 关键字返回内容
将内容 返回到 函数调用处
函数体中没有 return 语句时,函数运行结束
则默认返回 None , 也被称为隐含返回值 -
表达式:
def function_name(param):
return param
res = function_name(param) -
eg. :
# 小栗子:
# 摄氏度与华氏度关系如:摄氏度/1.8 + 32 = 华氏度
# 需求:
# 定义函数1:用于输出摄氏度
# 定义函数2:通过摄氏度计算得出华氏度
def c_temp():
c_t = -3
print(f"今天摄氏度:{c_t}℃")
return c_t
def f_temp(n):
f_t = round(n/1.8) + 30
print(f"今天华氏度:{f_t}℉")
if __name__ == "__main__":
res = c_temp()
f_temp(res)
Run:
今天摄氏度:-3℃
今天华氏度:28℉
函数多个返回值
- 当执行函数体内代码时,遇到第一个 return 就将指定值返回到函数调用处,也就是执行到return这行代码,后面的都不执行了。
- 多个返回值时,用逗号隔开,但默认为元组。
- 格式:
def function_name(param1,param2):
return param1
return param2
res = function_name(param)
函数的作用域
作用域介绍
- Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
- 变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python 的作用域一共有4种,分别是:
L(local):局部作用域,即函数中定义的变量;
E(enclosing):嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
G(global):全局变量,就是模块级别定义的变量;
B(build-in):内建作用域,系统固定模块里面的变量,比如:int()等;
global 关键字
- 当我们需要在函数内部直接修改全局变量时,我们可以将函数内部的局部变量通过 global 关键字声明为全局变量。
函数作用域的优先级

递归函数
递归的介绍
函数Func(args)直接或间接调用函数本身,则该函数称为递归函数。
tips:
-
递归函数自身没有结束条件,所以需要我们自己设置结束条件,终止函数的调用。
-
可以使用递归实现的循环都可以实现,并且递归效率很低,所以递归很少使用。
-
eg. :
# 小栗子:
# 阶乘本质:n! = 1 * 2 * 3 * ... * n
def get_nums(num):
if num > 1:
return num*get_nums(num - 1)
else:
return 1
res = get_nums(4)
print(res)
Run:
24
内置文件中常用方法
range()
- range(start,stop,step) --> range object
- 步长step不能为小数。(0.5 / 1.5 / …)

-eg. : 实现返回1-10的奇数列表
li = []
for i in range(1, 11, 2):
li.append(i)
print(li)
Run:
[1, 3, 5, 7, 9]
zip()
- zip()用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
- zip(iter[,iter2 […]]) --> zip object
map()
- map() 会根据提供的函数对指定序列做映射。
- map(func, *iterables) --> map object
filter()
- filter() 用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
- filter(func, iterable) --> filter object

匿名函数lambda
匿名函数介绍
- 当我们在传入函数时,有些时候,不需要重复调用该函数,直接传入匿名函数更方便,也无需担心函数名冲突,并且还可以将匿名函数赋值给一个变量,再利用变量来调用该函数。
语法 :lambda x:x*x

匿名函数应用
# lambda 形参:返回值
f = lambda x, y: x * y
print(f(2, 5))
# n!
from functools import reduce
print(reduce(lambda x, y: x*y, range(1, 4)))
# 匿名函数作为返回值
def fx(i, j):
# 返回的匿名函数
return lambda :i*j
f = fx(6, 6) # lambda :i*j
print(f()) # 函数只有在调用时才会执行
# 匿名函数作为实参
def test(a, b, func):
res = func(a, b) # 11 + 22
return res
nums = test(11, 22, lambda x, y: x+y)
print(nums)
Run:33
- sort 与 sorted 区别:
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
# [4,-2,3,1] --> [1,-2,3,4]
# [4,2,3,1] --> [1,2,3,4] --> [1,-2,3,4]
li = [4, -2, 3, 1]
# key:指定排序规则,排序之后返回原元素
li.sort(key=abs)
print(li)
高阶函数
- 高阶函数需满足条件:
函数名 作为 参数传入
函数名 作为 返回值
拓展1:值类型与引用类型,传值调用与传引用调用的区别
本段引用来至:值类型与引用类型,传值调用与传引用调用的区别
值类型
- 指基本类型
- 整型: byte,short,int,long
- 浮点型:float,double
- 字符型:char
- 逻辑型:boolean
-
引用类型
除了四类八种基本类型外,所有的类型都称为引用类型(如:数组,类,接口,字符串) -
值传递
基本数据类型赋值都属于值传递;
值传递传递的是实实在在的变量值,是传递原参数的拷贝,值传递后,实参传递给形参的值,形参发生改变而不影响实参。 -
特点:
此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。 -
引用传递
引用类型之间赋值属于引用传递;
引用传递传递的是对象的引用地址,即它的本身; -
特点:
在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。 -
传值调用
方法调用时,实际参数把它的值的副本传递给对应的形式参数,形参的变化与实参无关。 -
引用调用
方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;允许调用函数修改原始变量的值。
拓展2:python中函数值传递与引用传递
本段引用来至:python中函数值传递与引用传递
-
第一个问题:值传递与引用传递
简单理解,值传递就是在一个参数传入到函数中后,函数中对该参数的操作不会影响函数外该参数的变量的值;而引用传递,则是参数传递进来的相当于内存地址,对该参数的操作会直接影响到外部指向其值的变量。 -
结论
python中的变量没有类型,变量相当于一个指针,可以指向任何类型的对象,也就是变量引用了某个对象;python对象是有类型的,一般看变量是什么类型需要看其引用的对象是什么类型。 -
python中没有严格的定义值传递与引用传递,总的看来,函数传递参数都可以看做是引用传递的(因为python变量相当于指针,传递指针就相当于传递了地址的引用),只不过因为python中的有些对象是不可变的,因此让有些值传递的过程中又像是值传递的。
-
当python中的函数传递过来的是不可变的值时(比如数字常量、元组和字符串),相当于 C语言中的值传递的;若传递过来的参数是可变的(如列表、字典等),则相当于引用传递。
不可变的对象作参数
看个例子:
x = 10
print("xid=",id(x))
def A(x):
print("axid=",id(x))
return x
def B(x):
x += x
return x
print("ax=",A(x))
print("bx=",B(x))
print("x=",x)
结果为:
xid= 140718279271088
axid= 140718279271088
ax= 10
bx= 20
x= 10
- 当x传递进函数的时候,会被当作一个局部变量,也就是会新开辟一个空间存放变量,该变量引用了参数的引用。因为原参数引用的是一个不可变的对象,所以局部变量会与函数外的变量指向同一个内存区域;该局部变量不会影响函数外的变量,但在函数内给x重新赋值的时候,会重新生成一个对象,并让局部变量x指向新的对象,而外部变量x不变。因此相当于值传递。
当传递的对象是可变对象时
x = [10]
print("xid=",id(x))
def A(x):
print("axid=",id(x))
return x
def B(x):
x += x
return x
print("ax=",A(x))
print("bx=",B(x))
print("x=",x)
结果为:
xid= 2769750468232
axid= 2769750468232
ax= [10]
bx= [10, 10]
x= [10, 10]
- 原理与上面的类似,但有区别,x传递进函数仍然可以看作生成了一个局部变量x,其引用了外部变量x的引用,与不变的对象的运算不同的是,此时的x += [10] 操作,不会生成新的列表对象,而是修改了原来存储空间中的列表对象,因此外部的x的值也会跟着改变。
下面的例子与传递不可变参数时是一样的:
x = [10]
print("xid=",id(x))
def A(x):
print("axid=",id(x))
return x
def B(x):
x = [10,10]
print("bxid", id(x))
return x
print("ax=",A(x))
print("bx=",B(x))
print("x=",x)
结果为:
xid= 2769750458632
axid= 2769750458632
ax= [10]
bxid 2769750460616
bx= [10, 10]
x= [10]
这里是因为赋值号=生成了新的列表导致了局部变量x指向了新的对象,原对象不变。
总结
python中的值传递与引用传递是一个相对的概念,原值有没有变化关键在原来的变量引用的对象有没有发生改变,而这些需要根据变量引用的对象来判断。
作业:

- 作业3

作业答案:
题1:
# 前一次做了!
- Run:
- Amy的答案:
def get_sum(num_a, num_b, num_c):
return num_a + num_b + num_c
def get_avg(num_sums, len_li):
num_avg = round(num_sums / len_li, 2) # round(object, 2),2代表小数点后精确到位数为2,默认为0.
print(f"和为:{num_sums}\n均值为:{num_avg}")
if __name__ == "__main__":
ipt_li = list(map(float, input("请输入:").split())) # split():拆分字符串。通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(list),默认分隔符为空格
num_sums = get_sum(*ipt_li)
get_avg(num_sums, len(ipt_li))
-Run:
请输入:45 63 63
和为:171.0
均值为:57.0
题2:
法2:
tips:
- Amy提示的isinstance()真好用呀!get到了!
- 重新认识了 *args 和 *。
- 尝试了用递归没成功,等答案吧!
def opt_tu(*args): # 此处的* 代表可变长度参数前的*
print(*args, sep="\n")
if __name__ == "__main__":
li = ["jack", ("tom", 23), "rose", (14, 55, 67)]
for i in range(0, len(li)): # for i in range li:这样更好
if isinstance(li[i], tuple): # 测试了也可以这样写 if type(li[i]) == type(()):
opt_tu(*li[i]) # 此处的* 代表拆包
else:
print(li[i])
-
Run:
jack
tom
23
rose
14
55
67 -
Amy的答案:递归!
def get_ele(l):
if isinstance(l, (int, str)):
print(l)
else:
for item in l:
get_ele(item)
l = ["jack", ("tom", 23), "rose", (14, 55, 67)]
get_ele(l)
Run:
jack
tom
23
rose
14
55
67
题3:
infors = [{'name': 'qian', 'age': 28}, {'name': 'amy', 'age': 20}, {'name': 'james', 'age': 25}]
print(sorted(infors, key=lambda s: s['name']))
-
Run:
[{‘name’: ‘amy’, ‘age’: 20}, {‘name’: ‘james’, ‘age’: 25}, {‘name’: ‘qian’, ‘age’: 28}] -
Amy的答案:
infors = [{'name': 'qian', 'age': 28}, {'name': 'amy', 'age': 20}, {'name': 'james', 'age': 25}]
infors.sort(key=lambda x: x["name"])
print(infors)
- Run:
[{‘name’: ‘amy’, ‘age’: 20}, {‘name’: ‘james’, ‘age’: 25}, {‘name’: ‘qian’, ‘age’: 28}]
End !
Best wishes for you!
本文介绍了Python编程中的函数概念,包括函数的返回值、作用域及其优先级、递归函数的使用。还探讨了内置文件方法如range()、zip()、map()和filter(),以及匿名函数lambda和高阶函数的应用。通过实例讲解了值类型与引用类型的差异,以及Python中函数的值传递和引用传递特性。
2193

被折叠的 条评论
为什么被折叠?



