02. 函数的可变长参数、函数嵌套、名称空间与作用域

一、可变长参数

可变长参数是指,调用函数的时候传入的实参个数不固定
而实参是为形参赋值的,相应的也要有新的形参格式来接收溢出的实参

1.1 形参名前加*

*号会把溢出的位置实参存成元组,然后赋值给后面的形参名
*后面的形参名通常使用args

如:

def func(x, y, *args):
    print(x, y, args)

func(1, 2)         # 1 2 ()   *z可以不被赋值
func(1, 2, 3, 4, 5)   # 1 2 (3, 4, 5)   实参个数可以溢出,但是不能少于位置实参的个数,

1.2 形参名前加**

**号会把溢出的关键字实参存成字典,然后赋值给后面的形参名
**后面的形参名通常使用kwargs

如:

def func(x, y, **kwargs):
    print(x, y, kwargs)


func(1, 2, a=111, b=222, c=333)  #  1 2 {'a': 111, 'b': 222, 'c': 333}
func('name' = 'jason', x = 1, y = 2, 'age' = 18) # 1 2 {'name':'jason','age':18}				

1.3 实参前加*

*会把其后的实参打散成位置实参
*号后跟的那个值应该是一个可以被for循环遍历的值

如:

func(*(111,222,333))  # func(111,222,333)
func(*"hello")        # func("h","e","l","l","o")

1.4 实参中带**

**会把后面的那个值打散成关键字实参
**后跟的那个值应该是一个字典

如:

func(**{"x": 111, "y": 222, }) 就相当于 func(y=222,x=111)

1.5 在形参与实参中混用*、**

形参中***是汇总操作
实参中***是打散操作

如:

def func(*args, **kwargs):  # args = (1,2,3)  kwargs = {'a':1, 'b':2}
    print(args, kwargs)  # (1, 2, 3) {'a': 1, 'b': 2}


func(*(1, 2, 3,), **{'a': 1, 'b': 2})  # func(1, 2, 3, 'a'= 1, 'b'= 2})

1.6 命名关键字形参(了解)

def func(x, y=222, *args, n=777,m, **kwargs):  # m,n必须按照关键字实参的格式为其赋值,其中n可以不被再次赋值
    print(x)  # 1
    print(y)  # 2
    print(args)  # (3,4,5)
    print(m)  # 66666
    print(n)  # 88888
    print(kwargs)  # {'a':11, 'b':22, 'c':33}

func(1, 2, 3, 4, 5, n=88888,m=66666, a=11, b=22, c=33)

二、函数对象

在python中,函数时第一类对象,简称函数对象
函数对象指的是函数可以当成变量一样去使用	

2.1 可以被赋值

def func():
    print('from func')

f = func  # 函数名func所指向的的内存地址绑定给了f
f()  # f()也可以进行函数调用

2.2 可以当做一个参数传给另一个函数

def func(aaa): # aaa=函数foo的内存地址
    print(aaa)
    aaa()      # 只能在func()内调用aaa()

def foo():
    print('from foo')

func(foo)   # 将foo赋值给了变量aaa,那么aaa()也可以当做foo()使用来调用函数

2.3 可以当成一个函数的返回值

def func(aaa):   # aaa=函数foo的内存地址
    return aaa   # 返回的是函数foo的内存地址

def foo():
    print('from foo')


res=func(foo)    # 将foo赋值给aaa
res()            # 相当于foo()

2.4 可以当做容器类型的元素

def foo():
    print('from foo')

l=[foo]
l[0]()   # 即 foo(),一样可以调用函数

三、函数的嵌套

3.1 函数的嵌套调用

在调用一个函数的过称中又调用了另一个函数

如取四个值的中的最大值:


def max2(x, y):
    if x > y:
        return x
    else:
        return y


def max4(a, b, c, d):
    res1 = max2(a, b)
    res2 = max2(res1, c)
    res3 = max2(res2, d)
    return res3


print(max4(1, 2, 3, 4))      

3.2 函数的嵌套定义

在一个函数内又定义了另一个函数

如:

def f1():
    def f2():
        print('from f2')

    f2()
f1()

特点:

嵌套定义在函数内的函数,正常情况下,只能在函数体内调用

四、名称空间与作用域

4.1 名称空间

即存放名字的地方

1、内置名称空间

存放的是内置的名称,如:print、int、len
生命周期:解释器启动就产生,期间一直存在,解释器关闭就销毁

2、全局名称空间

存放的是顶级代码中的名字
生命周期:python程序运行时创建,程序顶级代码运行结束时销毁

3、局部名称空间

存放的是函数内的名字
生命周期:函数调用时创建,调用完毕就立即销毁

4.2 名称空间的查找优先级

基于现在的位置向外查找
具体的:局部—>外层套的局部—>外层套的局部—>…—>全局—>内置
ps:名称空间的嵌套关系是函数定义阶段(检测语法的时候)就已经确定好的,与调用的位置无关
如:

x = 111

def f1():
    print(x)  #定义f1时,x=111,  后面x如何变化都与f1内的x绑定的值(内存地址)无关

def f2():
    x = 222
    f1()

f2()  # 111

4.3 作用域

① 全局作用域/全局范围:内置名称空间、全局名称空间
   			   特点:全局存活、全局有效
   	
② 局部作用域/局部范围:局部名称空间
   			   特点:临时存活,局部有效

4.4 函数参数的传递

1、对于全局定义的不可变类型,不可以在函数内直接修改

x = 10
def func(a):  # 调用时a=10的内存地址
    a = 123   # 123的存地址绑定给a,a与10的内存地址解除绑定
    
func(x)   # x=10的内存地址
print(x)  # 10

2、对于全局定义的可变类型,可以在函数内直接修改

x = []
def func(a):  # a=列表的内存地址
    a.append(1111)

func(x)   # x=列表的内存地址
print(x)  # [1111]

3、使用 global,可以在函数内修改全局定义的不可变类型数据

x = 10

def func():
    global x  # 声明变量来自于全局
    x = 666
    
func()
print(x)  # 666

4、使用 nonlocal可以修改外层函数的局部空间变量

x = 10

def f1():
    x = 11

    def f2():
        nonlocal x
        x = 666

    f2()
    print(x)  # x被f2修改成了666


f1()      # x = 666
print(x)  # 10
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值