16.Python基础篇-函数
函数的基本使用
函数的含义:
函数是执行特定任务的独立代码块,函数可以接受参数,并返回值,帮助我们简化代码,并在不同地方复用相同的功能。
特点:可读性强,可复用性强
函数的定义与调用
定义:
使用def关键字定义一个函数
def 函数名(参数1,参数2): 函数体 return返回值
调用语法
函数名(参数) # 方式一:调用函数,不接受返回值 返回值 = 函数名(参数) # 方式二:接收函数的返回值,赋值给一个变量
函数的参数,分为形参与实参
形参与实参:形参是在定义函数时,用来指定函数可以接收的参数名称;实参是在调用函数时,传递给函数的真实值。实参是传递给形参的具体数据。
形参:
位置参数
def func(a, b): print(a + b)
默认参数
def func(a, b=1): # b为默认参数,默认值为1 print(a + b) # 将1赋值给a,b使用默认值,默认值为1。则输出结果为:2 func(1) # 默认参数可以不传 # 将1复制给a,b赋值为3,不使用默认值。输出结果为:4 func(1, 3)
可变参数:*args
args,只是一个变量名,可以自定义,但是一般都使用args(约定俗成)
def func(*args): # args实际为一个元组,传入的每一个参数为元组中一个元素 print(args) func(1) # 可以传1个值 func(1, 2, 3, 4) # 也可以传多个值
可变参数:**kwargs
kwargs,只是一个变量名,可以自定义,但是一般都使用kwargs(约定俗成)
def func(**kwargs): # kwargs实际为一个字典,接收到的参数存储为键值对 print(kwargs) func(name='mingbo', age=18) # 往kwargs这个字典中传入两个键值对 # 输出: {'name': 'mingbo', 'age': 18}
定义形参的顺序
位置参数--->*args--->默认参数-->**kwargs
def func(name, *args, age=18, **kwargs): print(name) print(args) print(age) print(kwargs) # mingbo赋值给name # (1,2,3)赋值给args # 19赋值给age # {sex:男}赋值给kwargs func('mingbo', 1, 2, 3, age=19, sex='男') # 输出: 邵明博 (1, 2, 3) 19 {'sex': '男'}
实参
按照位置传参
def func(a, b): print(a, b) func(1, 2) # 按照位置传参,将1传给a,2传给b # 输出: 1 2
按照关键字传参
def func(a, b): print(a, b) func(a=1, b=2) # 按照关键字传参 # 输出: 1 2
*args和**kwargs可以使用星号*和**传入一个List、字典。
def func1(*args): print(args) li = [1, 2, 3, 4] func1(*li) # 将li这个列表中的元素,分别传入到args中 # 输出:(1, 2, 3, 4) def func2(**kwargs): print(kwargs) dic = {'name': 'mingbo', 'age': 18} func2(**dic) # 将dic这个字典中的键值对,分别传入到kwargs中 # 输出:{'name': 'mingbo', 'age': 18}
传参的注意点:位置参数必须在关键字传参之前。
def func(a, b): print(a, b) func(1, b=2) # 位置传参与关键字传参混合使用 # 输出: 1 2
函数的返回值
1.没有返回值(不写return)
不写return
def func(): pass print(func()) # 不写return,默认返回None # 输出: None
只写return
def func(): return print(func()) # 只写return,默认也返回None # 输出: None
return None
def func(): return None print(func()) # 返回None # 输出: None
2.返回1个值
结束函数,并返回一个值
def func(a, b): return a + b ret = func(1, 2) # 接收返回值,存储到变量ret中 print(ret) # 输出: 3
3.返回多个值:多个值之间使用英文逗号隔开,实际返回的是一个元组,每个返回值为其中的一个元素。
用1个变量接收
def func(a, b): return a, b # 实际返回的是一个元组(a, b),每个返回值为其中一个元组 ret = func(1, 2) # 使用1个参数接收返回值 print(ret) # 输出为元组类型的(1, 2) #输出: (1, 2)
用等量的多个变量接收
def func(a, b): return a, b a, b = func(1, 2) # 使用变量a和b,分别接收1和2 print(a, b) # 输出a和b # 输出: 1 2
注意点
1.先定义后调用
2.只定义不调用,就一定不会执行
3.默认参数的陷阱:如果默认参数的值是一个可变教据类型,那么每一次调用函数的时候,如果不传值就公用这个数据类型的资源
def func(li=[]): li.append(1) print(li) func() # 输出:[1] func() # 输出:[1, 1] func([]) # 输出:[1] func() # 输出:[1, 1, 1]
命名空间与作用域
三种命名空间
1.内置命名空间--- python解释器
就是python解释器一启动就可以使用的名字,存储在内置命名空间中。
内置的名字在启动解释器的时候被夹在进内存里。比如print、input等
2.全局命名空间----我们自己写的代码,但不是函数中的代码
是在程序从上到下被执行的过程中依次加载进内存的
放置了我们设置的所有变量名和函数名
3.局部命名空间----函数中
就是函数内部定义的名字
当调用函数的时候,才会产生这个名称空间。随着函数执行的结束 这个命名空间就又消失了。
x = 10 # x 为全局变量 def func1(): # func1这个函数名也是全局变量 y = 20 # 函数体中的y为局部变量
调用顺序
当前名字空间有该名字的时候,就不找上一级要了;如果当前名字空间没有,就会找上一级要。如果一直到内置的名字空间都没有,就会报错。
局部命名空间中有该名字,则优先使用局部的;
局部命名空间中没有改名字,则使用全局的;
如果全局也没有,则使用内置的;
如果内置也没有,则报错。
作用域
全局作用域
作用在全局,内置和全局命名空间中的名字都属于全局作用域。
局部作用域
作用在局部,函数(局部命名空间中的名字属于局部作用域)
注意点:
1.多个局部命名空间之间是隔离的,不能共享。并且只能是局部用全局、内置的,或者是全局用内置的,反过来则不行,比如:
内置不能使用全局,全局也不能用局部。
2.对于不可变数据类型,局部只能查看全局作用域中的变量,不能修改。如果修改,需要在程序开始处天剑global生命。
如果在一个局部(函数)内生命了一个global变量,那么这个变量在局部的所有操作会对全局的变量有效。
相关方法及关键字
global关键字
用于在函数内部声明变量为全局变量。使用 global
允许你在函数中修改全局作用域中的变量,而不是创建一个局部变量。
x = 10 # x为全局变量 def update_global(): global x # 声明 x 为全局变量,声明之后可以修改 x += 5 # 修改全局变量 update_global() print(x) # 此时的全局变量已经在方法中被修改,并且全局生效。 输出:15
globals()方法
打印全局变量的名字
x = 10 y = 20 def func(): z = 10 print(globals()) 输出: {... 'x': 10, 'y': 20, 'func': <function func at 0x100cba7a0>}}
nolocal
nonlocal
关键字用于在嵌套函数(即函数内部定义的函数)中声明一个变量,它作用于最近的外层函数的作用域,而不是全局作用域。使用 nonlocal
关键字可以在内层函数中修改外层函数中的局部变量。
def outer_function(): x = "outer" def inner_function(): nonlocal x # 声明 x 来自外层函数 x = "inner" # 修改外层函数的局部变量 inner_function() print(x) outer_function() 输出结果: inner
globals与nolocal的区别
nonlocal
只影响最近的外层函数的作用域,还是局部作用域;而 global
影响全局作用域。
locals()方法
根据调用的位置所处的作用域,打印当前作用域下的名字。
x = 10 y = 20 def func(): z = 10 print('局部作用域中使用locals:' + str(locals())) # 在局部作用域中使用,会返回局部作用域的变量 func() print('全局作用域中使用locals:' + str(locals()))# 在全局作用域中使用,会返回全局作用域的变量 #输出结果: 局部作用域中使用locals:{'z': 10} 全局作用域中使用locals:{... 'x': 10, 'y': 20, 'func': <function func at 0x1049867a0>}
基础阶段总结:
在局部:可以使用全局、内置命名空间中的名字。
在全局:可以使用内置命名空间中的名字,但是不能用局部的。
在内置:不能使用全局的和局部的