1.函数定义
def 函数名(形参):
'''注释'''
函数体
return 返回值
函数名:只能包含字母、数字、下划线且不能以数字开头。函数名尽量简短,并能表达函数功能。
函数名的本质就是函数的内存地址(可被引用、可被当作函数的参数和返回值、可被当作容器类型的元素)
注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。
返回值:如果没有return,默认返回值为None;返回值可以有一个或者多个,多个返回值作为一个元组被返回。
调用:函数名(实参)
参数类型:位置参数、默认参数、动态参数。
位置参数
1)按照位置传值
2)按照关键字传值
3)位置、关键字混用
def func(a,b):
print(a,'***',b)
func(1,2) # 1 *** 2 按位置传参
func(b=2,a=1) # 1 *** 2 按关键字传参
# func(a=1,2) # 错误
func(1,b=2) # 1 *** 2 位置和关键字混用
特别注意:
①位置、关键字传值混用时,位置参数必须在关键字参数的前面;
②一个形参只能赋值一次;
③位置参数必须传值。
默认参数(将参数值变化小的参数设置为默认参数)
def fun(a,b=1):
print(a,'>>>',b)
fun(3) # 3 >>> 1
fun(3,3) # 3 >>> 3
特别注意:当默认参数类型为可变数据类型时的陷阱
如果默认参数的值是一个可变的数据类型,那么每一次调用函数使用默认参数值时,这个参数相当于一个全局变量,会受其他几次调用的影响。
def funcc(a,b=[]):
b.append('aabb')
print(a,'&&&',b)
funcc(1) # 1 &&& ['aabb']
funcc(2,[2]) # 2 &&& [2, 'aabb']
funcc(3) # 3 &&& ['aabb', 'aabb']
funcc(4,[4]) # 4 &&& [4, 'aabb']
funcc(5) # 5 &&& ['aabb', 'aabb', 'aabb']
动态参数
*args(任意多个位置参数),组成的是元组;**kwargs(任意多个关键字参数),组成的是字典;*args,**kwargs组合使用,可以传任意个参数。
特别注意:*args必须在**kwargs之前 。
def sum(*args):
'''数字求和'''
cal = 0
for i in args:
cal += i
return cal
print(sum(1,2,5,7)) # 15 与下面传参方式等价
print(sum(*[1,2,5,7])) # 15 列表前加上*,就是将列表按照顺序打散
def funs(**kargs):
for i in kargs:
print(i,'@@@',kargs[i])
funs(name='maty',sex='male') # 与下面传参方式等价
funs(**{'name':'maty','sex':'male'}) # 字典前加上**,就是将字典打散
# sex @@@ male
# name @@@ maty
def gun(*args,v=[1],**kwargs):
print(v)
for i in args:
print(i)
for i in kwargs:
print(i,'@@@',kwargs[i])
gun(1,7,v=[2],a=3,b=4)
#[2]
# 1
# 7
# b @@@ 4
# a @@@ 3
三种类型参数顺序:必须先定义位置参数,再定义动态参数*args,再默认参数,再动态参数**kwargs
2.命名空间
命名空间存放名称与值的对应关系。
命名空间的类型:全局命名空间global、局部命名空间local、内置命名空间built-in
1)内置命名空间-- python解释器一启动就可以使用的名字,存储在内置命名空间中,如list()... 。内置的名字在启动解释器的时候被加载进内存。
2)全局命名空间--编码者写的除函数内的代码。程序从上到下执行的过程中依次加载进内存 ,放置了我们设置的所有变量名和函数名。
3)局部命名空间--函数内部定义的名字 。当函数调用的时候,产生此名称空间,随着函数执行的结束,这个命名空间被释放了。
命名空间加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
命名空间的取值顺序:
1)局部调用时,局部命名空间->全局命名空间->内置命名空间,如果局部没有就会找上一级全局要,全局没有再找内置要,不能逆向。
2)全局调用时,全局命名空间->内置命名空间,如果全局没有就找内置要。
x=10
def fung(x):
print(locals())
print(x)
fung(20) # 20 局部变量
print(x) # 10 全局变量
print(min) # <built-in function min> 内置函数
3.作用域
作用域就是作用范围。
作用域分类:全局作用域和局部作用域。
1)全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效。
内置函数globals(),可查看所有的全局名称。
2)局部作用域:局部名称空间,只能在局部范围内生效。
内置函数locals(),放在函数中可查看所有的局部名称,但是放在全局作用域则和globals()查询结果相同
作用域中关键字。
1)global关键字。
对于不可变数据类型,在局部可查看全局作用域中的变量,但不可直接修改,如果想修改,须在程序一开始添加global声明。 如果一个局部内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效 。
y = 10
def fund():
y=11
print(y)
fund() # 11 局部变量
print(y) # 10 全局变量
修改全局变量
y = 10
def fund():
global y
y = 11
print(y)
fund() # 11 全局变量
print(y) # 11 全局变量
2)nonlocal关键字。
nonlocal只能用于局部变量(对全局无效),声明了一个上层局部变量(离得最近的局部变量),从而可以修改上层局部变量的值。
def fun1():
x = 3
def fun2():
nonlocal x
x = 4
print(x)
fun2() # 4
print(x) # 4
fun1()
4.闭包
闭包函数:内部函数包含对外部作用域而非全局作用域名称的引用。
# 内部函数名.__closure__,有cell说明是闭包,如果为None,则非闭包函数
def outer():
a = 1 # 外部函数变量
def inner():
print(a) # 内部函数调用外部函数的变量
print(inner.__closure__) # (<cell at 0x0000021F7872ADF8: int object at 0x000000006357EF30>,)
return inner
inn = outer() # 获得inner内存地址
inn() # 1 调用inner函数