10 函数 Function
##1 函数的定义 使用关键字`def = define`来进行定义 定义函数的目的: 1.最大化代码重用,dry原则(don't repeat yourself) 2.最小化代码冗余 3.过程分解 函数的定义:`def 函数名称(形参):`2 函数的调用
函数名称(实参)
def learning(name, course, start, end):
print('{} is learning {}'.format(name, course))
print('{} to {}'.format(start, end))
learning('Jerry', 'python入门经典', '2018/7', '2018/9')
3 函数的返回值
使用return
来返回函数的值,python具有多态
的特性,而可以实现不同类型的计算,然后返回。
def add_num(x, y): return (x + y)
print(add_num(3, 5))
例子,找出两个序列中的重复部分:
这个例子可以实现多态的特性,实参只要是序列就可以了,可以是list也可以str类型
def intersect(seq1, seq2):
res = []
for x in seq1:
if x in seq2:
res.append(x)
return res
seqA = [1, 5, 65, 8, 4, 5, 4]
seqB = [1., 2, 45, 1, 65, 4]
print(intersect(seqA, seqB))
结果:[1, 65, 4, 4]
同样也可以通过集合set
来实现得出两个不同的元素
seqA = [1, 5, 65, 8, 4, 5, 4]
seqB = [1, 2, 45, 1, 65, 4]
s1 = set(seqA) & set(seqB)
print(s1)
结果:{65, 4, 1}
4 函数的作用域
4.1 函数内的变量的作用域
1.函数里面定义的变量成为local
,作用域为函数内部。
2.函数外部定义的是global
全局的变量
3.另外的是built-in
内置的类型,其作用域最高
# 函数内的变量的值和外部变量重复了
# 函数内的变量的作用域的问题
x = 50
def fun():
x = 99
return x
print('函数运行后的x的值是{}'.format(fun()))
print('全局的x的值是{}'.format(x))
结果:
函数运行后的x的值是99
全局的x的值是50
4.2 在函数的内部使用global
关键字的变量
可以在函数中使用global
关键字来声明该变量为全局的变量
# 函数内的变量的值和外部变量重复了
# 函数内的变量的作用域的问题
x = 50
def fun():
global x
x = 99
return x
print('函数运行后的x的值是{}'.format(fun()))
print('全局的x的值是{}'.format(x))
结果:
函数运行后的x的值是99
全局的x的值是99
4.3 python3中的封装enclosure
使用场景为函数中又嵌套了函数,嵌套的函数变量和上一层的函数的变量名称相同,可以使用nonlocal
关键字。
优先级的顺序:LEGB
4.3.1 函数中嵌套函数的作用域
从下面的例子可以看出函数变量的作用域,其中enclosure
的优先级是最低的,其次是local
,然后是global
,最后是built-in
x = 10
def f1():
x = 99
def f2():
x = 100
print(x)
print(x) # 打印的是f1 local的x
f2() # 打印的是f2 local的x
print(x) # 打印的是f1 local的x
f1()
print(x)
结果:
99 # 打印的是f1的
100 # 打印的是f2的
99 # 打印的是f1的
10 # 打印的是global的
如果要在嵌套的函数中使用全局的,就使用global
的关键字,如果只是想使用外侧的,就使用nonlocal
的关键字来实现。
x = 10
def f1():
x = 99
def f2():
nonlocal x
x = 100
print(x)
print(x) # 打印的是f1 local的x
f2() # 打印的是f2 local的x
print(x) # 打印的是f1 local的x
f1()
print(x)
结果:
99
100
100
10
4.3.2 Built-in
如果定义了一个方法,将built-in覆盖了,就会使用定义的函数,编写的时候特别注意,不要覆盖了built-in的函数。
5 函数的参数传递
变量类型,大致可以分为2种,一种是可变类型,另外一种是不可变类型。
5.1 传递实参是不可变类型
不可改变的类型,如int类型,作为参数传递到函数,此时是作为副本传递,实参的值是不会改变的。
例子1,传递的是一个int类型
def change_num(x):
x += 10
x = 5
change_num(x)
print(x)
结果:
5
例子2,传递的是一个str类型
def change_num(x):
x += 'abc'
x = 'Hellokitty'
change_num(x)
print(x)
结果:Hellokitty
5.2传递实参是可变类型
可改变类型作为实参,传递给函数,函数进行的操作,会改变可变类型的本身的值,如下的list的类型。
def change_num(x):
x[0] = '99'
x = [1,2,3]
change_num(x)
print(x)
结果:['99', 2, 3]
如果我想传递一个list但是又不想改变,可以手动传递副本,而不是直接传递值,这里本质上浅拷贝,如果有列表嵌套也不会奏效。
def change_num(x):
x[0] = '99'
x = [1, 2, 3]
change_num(x[:])
print(x)
5.3传递可变和不可变实参的原理
传递可变类型,实际是传递的一个值,而不可变的类型传递的是一个引用。
6 函数的参数的匹配
6.1传递安装顺序传递,位置匹配
默认情况下是安装位置的顺序进行匹配的
def func(a, b, c):
print(a, b, c)
func(1, 2, 3)
func('a', 'b', 'c')
6.2传递参数,按照变量的值匹配
也可以通过指定参数的值来进行参数的传递
def func(a, b, c):
print(a, b, c)
func(1, 2, 3)
func('a', 'b', 'c')
func(c=15, a=16, b=55)
6.3默认值传递值
在定义函数的时候,就可以将参数赋予默认值,在传递实参的时候可以传递部分值给形参。
但是要注意一点:定义函数的默认值只能放在最后面
def func(a, b=1, c=1):
print(a, b, c)
func(18)
func(1,15)
结果:
18 1 1
1 15 1
6.4函数接收多个不确定个数的参数*arg
python是一个动态类型,可以传递事先不确定个数的任意参数。
没有函数的重载,但是python设计可以在声明函数时,表明可以接收任意个数的参数,其中会将多余的参数以tuple的形式传递给arg
6.4.1python在定义函数的时候,在形参的前面加上*
来表明可以接收可变个数的参数:
def avg(*score):
return sum(score) / len(score)
print(avg(99, 100, 87, 75, 62))
print(avg(87, 99, 85, 68))
6.4.2 声明了接收可变参数,但传递的是一个元组,需解包
如果函数定义可以接收可变参数,但是将参数已经全部保存在一个tuple里面了,此时如果要传递这个tuple,需要先进行解包的操作。
# 如下会报错
def avg(*score):
return sum(score) / len(score)
t = (87., 94, 98, 78)
avg(t)
结果:
Traceback (most recent call last):
File "D:/str_2_unicode/str_2_unicode.py", line 7, in <module>
avg(t)
File "D:/str_2_unicode/str_2_unicode.py", line 2, in avg
return sum(score) / len(score)
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'
正确的操作如下,需要先进行解包的操作
def avg(*score):
return sum(score) / len(score)
t = (87., 94, 98, 78)
print(avg(*t))
结果:89.25
如下例子,将他直接进行传递,可以看到t作为一个参数被传递了,而并未被解开
def func(*args):
print(args)
t =(1,2,3)
func(t)
func(*t)
结果:
((1, 2, 3),)
(1, 2, 3)
6.4.3 函数实参为字典表
可以在定义函数的时候使用**
,将多余的参数以dict的方式来呈现。
例如,如果要处理一个员工的信息,包括 name,age,job,salary,当然可以使用4个形式参数,然后传递4个实际的参数到函数进行处理,如下:
def staff_info(name, age, job, salary):
print(name, age, job, salary)
staff_info('Jerry',20,'dev',9000.00)
结果:Jerry 20 dev 9000.0
但是有的时候,也不太确定要传递参数的个数,并且这些参数明显是具有相关性的,可以通过传递字典表来解决这个问题。
def func(**arg)
,使用**来表示将传递的多余部分以字典表方式处理
扩展阅读
https://www.cnblogs.com/xuyuanyuan123/p/6674645.html
要注意的是,传递的是一个键值对,其中键的值并不需要加上引号。
def staff_info(**kwargs):
print(kwargs)
staff_info(name='Lucy', age=20, job='dev', salary=11000)
结果:{'salary': 11000, 'age': 20, 'job': 'dev', 'name': 'Lucy'}
如果要传递的参数本身就已经是一个dict类型,需要进行解包操作。
def staff_info(**kwargs):
print(kwargs)
lucy_info = dict(name='Lucy', age=20, job='dev', salary=11000)
staff_info(**lucy_info)
如果不进行解包操作,则会报错:
def staff_info(**kwargs):
print(kwargs)
lucy_info = dict(name='Lucy', age=20, job='dev', salary=11000)
staff_info(lucy_info)
Traceback (most recent call last):
File "D:/str_2_unicode/str_2_unicode.py", line 7, in <module>
staff_info(lucy_info)
TypeError: staff_info() takes 0 positional arguments but 1 was given
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步