函数进阶
一、函数参数类型
可变类型参数与不可变类型参数
不可变类型参数:数字、字符串、元组
可变类型参数:列表、字典、集合
(1)不可变类型参数
fun(a)–内部修改a的值,只是修改了一个对象的副本,不会影响a本身
def fun(a):
a+=3
print('函数内部a=',a) # 13
x=10
hs(x)
print('函数外部x=',x) # 10
(2)可变类型参数
fun(la)–将真正的a传过去,修改后fun函数外部的la也会受到影响
def fun(a):
a.append(3)
print(a) # [1,2,3]
x=[1,2]
hs(x)
print(x) # [1,2,3]
def hs(a):
a['age']=19
print(a) # {'name':'张三','age'=19}
x={'name':'张三'}
hs(x)
print(x) # {'name':'张三','age'=19}
!!!注意
默认参数如果是可更改的类型,程序运行时将会出现逻辑错误
如下:
def hs(a=[]):
a.append(10)
print(a)
hs() # [10]
hs() # [10,10]
调用完函数,实参走后,对形参没有任何影响,除非再来
如下:
def hs(a=[]):
a.append(10)
print(a)
hs() # [10]
b=[9]
hs(b) # [9,10]
hs() # [10,10]
hs(b) # [9,10,10]
还有一点要特别注意
def hs(a):
a=[1,2]
b = [3,4]
hs(b)
print(b) # [3,4]
上述代码段的结果,似乎跟上面的知识不符诶,这是为啥?这里其实是因为,hs函数中的a=[1,2]是重新赋值,并不算是修改,所以当然也不适用于前面说的规则。
二、全局变量和局部变量
作用范围
(1)全局变量
在函数外部定义,全局变量的作用域是从定义位置起的整个程序
(2)局部变量
在函数中定义的变量称为局部变量,只能在函数内部生效
def hs():
b=3
print(a) # 6
print(b) # 3
a=6
hs()
# print(b) # 报错 name 'b' is not defined
注意!将局部变量与全局变量同名,函数内的以局部变量为准
‘自己家有,就用自己的’
def hs():
a=7
print(a) # 7
a=9
hs()
print(a) # 9
全局变量和局部变量,不可共存
def hs():
# print(a) # 报错 在使用之前未定义
a=9
print(a) # 9
a=10
hs()
print(a) # 10
还有只要出现了‘=’,包括‘+=’,都相当于重新开辟了一块内存空间
def hs():
a+=3 # 报错 在使用之前未定义
print(a)
a=10
hs()
三、global关键字和nonlocal关键字
1.global关键字
global关键字可以将局部变量变成一个全局变量
def hs():
global a
a+=10
print('函数内部:%d' % a) # 30
a=20
hs()
print('函数外部:%d' % a) # 30
def hs():
global a
a=10
hs()
print(a) # 10
def hs():
global a
a=10
# print(a) # 报错 name 'a' is not defined
hs()
print(a)
2.nonlocal关键字
nonlocal关键字可以修改外层(非全局)变量
def out():
a=9
def inside():
nonlocal a
a=98
print('我是内部',a) # 我是内部 98
inside()
print('我是外部',a) # 我是外部 98
out()
非全局体现在这里:
a=9
def out():
def inside():
nonlocal a # 报错 no binding for nonlocal 'a' found
a=98
print(a)
inside()
out()
综合例子:
a=9
def out():
a=7
def inside():
nonlocal a
a=999
print(a) # 999
inside()
print('-------------',a) # ------------- 999
out()
print(a) # 9
四、函数嵌套–enclosing
原理同局部变量
def outside():
def inside():
print('我是内部')
inside()
print('我是外部')
outside()
# inside() # 报错
结果:
我是内部
我是外部
def out():
a=9
def inside():
a=98
print('我是内部',a) # 我是内部 98
inside()
print('我是外部',a) # 我是外部 9
out()
五、全局变量类型
1.全局变量是不可变数据类型,函数无法修改全局变量的值
a=10
b=[]
def x():
a=8
b.append(9)
print(a) # 8
x()
print(a) # 10
print(b) # [9]
上述代码中,外部的a与内部的a没有任何关系
b=[]
def x():
a=8
b=[9]
print(b) # [9]
x()
print(b) #[]
上述代码中,外部的b与内部的b没有任何关系。虽然它是可变类型,但函数x内b=[9]的操作,不算修改,而是重新赋值了。
2.全局变量是可变数据类型,函数可以修改全局变量
b=[]
def x():
b.append(9)
x()
print(b) # [9]
六、命名空间
(一)三种命名空间
1.局部命名空间
记录了函数的变量,包括函数的参数和局部定义的变量
locals()–访问局部命名空间的函数
2.全局命名空间
记录了模块的变量,包括函数、类、其他导入的模块
glogals()–访问全局命名空间的函数
3.内置命名空间
存放着内置的函数和异常
a=3
b=4
def hs(x):
c=5
d=6
print(locals())
print(globals())
hs(6)
结果:
{'__name__': '__main__', '__doc__':...}
{'x': 6, 'c': 5, 'd': 6}
(二)命名空间加载顺序
内置命名空间->全局命名空间->局部命名空间
七、作用域
作用域按照变量的定义位置可以划分为4类,即LEGB
(一)分类
1.Local(函数内部)
2.Enclosing(嵌套函数的外部函数内部)
3.Global(模块全局)
4.Built-in(内建)
(二)命名空间查找顺序
(1)先在local中搜索
(2)然后在父函数的命名空间enclosing中搜索
(3)接着在模块命名空间global中搜索
(4)最后在内置命名空间built-in搜索
a=3
b=30
c=300
def out():
a=4
b=40
def inside():
a=5
print(a)#L local 优先使用本地的
print(b)#E enclosing 本地没有找嵌套作用域
print(c)#G globle 本地嵌套都没有,找全局
print(__name__)#B built-in 全局也没有,找内置
inside()
out()
!!!注意:模块、类、函数会产生新的作用域,其他代码不会
比如条件判断、循环语句、异常捕捉等的变量是可以全局使用的
x=18
if x<25:
b=20
print(b) # 20
八、函数
1.abs()–绝对值
a=-1
b=2
print(abs(a)) #1
print(abs(b)) # 2
2.max()–求最大值
注意变量名不要叫max!否则调用max()会出错
a=[1,3,2,5,4]
x=max(a)
print(x) # 5
a=[-1,-3,-2,-5,-4]
b=max(a)
print(b) # -1
在参数中加上key=函数名–指定求最大值的规则
绝对值最大:
a=[-1,-3,-2,-5,-4]
b=max(a,key=abs)
print(b) # -5
def hanshu(x):
print('---')
return abs(x)
a=[-1,-3,-2,-5,-4]
# 把函数名作为一个参数换地给了max(),max()内部执行了hanshu()
b=max(a,key=hanshu)
print(b)
结果:
---
---
---
---
---
-5
字典和字典是不能比较的,但可以利用age键的值比较:
lst=[{'name':'Tom','age':19},{'name':'jerry','age':29},{'name':'mary','age':39}]
def getAge(x):
return x['age']
b=max(lst,key=getAge)
print(b)
key=函数名也可用于sort函数
a=[-1,-3,-2,-5,-4]
# 升序排序
a.sort()
print(a) # [-5, -4, -3, -2, -1]
# 按照绝对值,升序排序
a.sort(key=abs)
print(a) # [-1, -2, -3, -4, -5]
3.map()–映射
第一个参数是一个函数名,这个函数返回的是加工过的值,第二个参数是可迭代的内容
函数会依次作用在迭代内容的每一个元素上进行计算,然后返回一个新的可迭代对象
def hs(x):
return x*x
a=[1,2,3]
b=map(hs,a)
print(b) # <map object at 0x0000000002142860>
# for x in b:
# print(x)
b=list(b)
print(b) # [1, 4, 9]
4.filter()–过滤序列
第一个参数是一个函数名,该函数返回的是True或False,第二个参数是序列
最后将返回True的元素放入新的可迭代对象
def gl(a):
if a%3==0 or a%7==0:
return True
else:
return False
a=[1,2,3,4,5,6,7,8,9]
b=filter(gl,a)
print(b) # <filter object at 0x0000000002662860>
print(list(b)) # [3, 6, 7, 9]
5.zip()–打包
接收任意多个可迭代对象作为参数
将对象中对应元素,打包成一个元组,然后返回一个可迭代的zip对象
若长度不同,以最短的为准
a=[1,2,3]
b=['a','b','c','d']
c=zip(a,b)
print(c)
for x in c:
print(x)
结果:
<zip object at 0x0000000002696D88>
(1, 'a')
(2, 'b')
(3, 'c')
zip()与map()搭配使用:
a=[1,2,3]
b=['a','b','c']
def hs(x):
return {x[0]:x[1]}
x=map(hs,zip(a,b))
print(list(x)) # [{1: 'a'}, {2: 'b'}, {3: 'c'}]
九、lambda–匿名函数
用来快捷定义一个小函数
不能包含循环、return,可以包含if…else…
表达式计算的结果直接返回
hs=lambda x,y:x+y
b=hs(2,3)
print(b) # 5
func=lambda :3<2
print(func()) # False
x=lambda a,b:a if a>b else b
print(x(2,3)) # 3
lst=[{'name':'Tom','age':19},{'name':'jerry','age':29},{'name':'mary','age':39}]
getAge=lambda x:x['age']
l=max(lst,key=getAge)
print(l)
hs=lambda x:x*x
a=[1,2,3]
b=map(hs,a)
print(list(b))
hs=lambda x:True if x%2==0 else False
hs=lambda x:not x%2
a=[1,2,3,4,5,6,7,8,9,10]
b=filter(hs,a)
print(list(b))
hs=lambda x:True if x%3==0 or x%7==0 else False
a=[1,2,3,4,5,6,7,8,9,10]
b=filter(hs,a)
print(list(b))
a=[1,2,3]
b=['a','b','c']
hs=lambda x:{x[0]:x[1]}
x=map(hs,zip(a,b))
print(list(x))
十、闭包
凡是内部嵌套函数用了外部资源时形成了闭包
资源就不会被回收,在函数运行完之后还存储在内存中
1
def hs():
x=3
def nb(n):
return x**n
return nb
b=hs()
print(b(2)) # 9
print(b(3)) # 27
利用匿名函数写:
def hs():
x=3
nb=lambda n:x**n
return nb
b=hs()
print(b(2)) # 9
print(b(3)) # 27
2
def func():
x=2
def nb(n,x=x):
return x**n
return nb
b=func()
print(b(3)) # 8
print(b(2,3)) # 9
3
def func():
x=2
return lambda n,x:x**n
b=func()
print(b(3,2)) # 8
print(b(2,3)) # 9
4
def hs():
a=[]
for i in range(3):
b=lambda y:y*i
a.append(b)
return a
z=hs()
print(z)
i=9
print(z[0](2)) # 4
print(z[1](2)) # 4
print(z[2](2)) # 4
重点!
过函数时,因为还没调用,函数内的语句不会执行
但因为已经加载了,所以默认参数已经赋值了
i=6
def x1(x=i):
print(x)
i=7
def x2(x=i):
print(x)
x1() # 6
x2() # 7
def hs():
a=[]
for i in range(3):
b=lambda y,i=i:y*i
a.append(b)
return a
z=hs()
print(z)
i=9
print(z[0](2)) # 0
print(z[1](2)) # 2
print(z[2](2)) # 4