Python基础学习(七)--函数进阶,全局局部,global,nonlocal,enclosing,命名空间,作用域,重要函数,lambda,闭包

本文深入讲解Python中的函数高级特性,包括参数类型、全局与局部变量、闭包等概念及其使用技巧,帮助读者掌握更复杂的编程任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数进阶

一、函数参数类型

可变类型参数与不可变类型参数

不可变类型参数:数字、字符串、元组
可变类型参数:列表、字典、集合

(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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值