Python day13:函数参数+函数对象+函数嵌套+名称空间+作用域

一:可变长参数
可变长指的是参数的个数不固定
站在实参的角度,实参是用来为形参赋值的,如果实参的个数不固定,那么必须要有对应的形参能够接收溢出实参
*与*在形参与实参中的应用
在形参中用*与*

1.1 在形参名前加 *:* 会把溢出的位置实参存成元组,然后赋值其后的形参名

def func(x,*y):  # y=(2,3,4)
    print(x)
    print(y)


func(1,2,3,4)
func(1)
func() # 位置形参x必须被传值

'''示范:'''
def add(*nums):
    res = 0
    for num in nums:
        res += num
    return res


res=add(1, 2, 3)
print(res)

1.2 在形参名前加**:**会把溢出的关键字实参存成字典,然后赋值其后的形参名

def func(x, **y):  # y=(2,3,4)
    print(x)
    print(y)


func(1,a=111,b=222,c=333)
func(a=111, b=222, x=1, c=333)
在实参中用\*与\**
def func(x, y, z):
    print(x, y, z)

1.3 在实参前加*:*会把其后的值打散成位置实参

nums = [1, 2, 3]
func(*nums)  # func(1,2,3)
 # 若只有一个形参,则多余出来的值没处放,会出错
def fun(x) 
    print(x)  

1.4 在实参前加 **:**会把其后的值打散关键字实参

dic = {'y': 111, 'z': 222, 'x': 333}
func(**dic)  # func(y=111,z=222,x=333)

'''
在形参与实参中混用*与**
'''
'''
同时使用*与**的作用是可以把外部传的值原封不动的传给另一个函数,这在闭包函数,装饰器中有很大作用
'''
def index(x,y,z,a,b,c):
    print("index===>",x,y,z,a,b,c)

def wrapper(*args, **kwargs):  # args=(1, 2, 3,)   kwargs={"a":111,"b":222,"c":333}
    index(*args, **kwargs)  # index(*(1, 2, 3,),**{"a":111,"b":222,"c":333})
                           #  index(1,2,3,c=333,b=222,a=111)


wrapper(1, 2, 3, a=111, b=222, c=333)

函数参数总结:

    # def func(x,y=222,*args,**kwargs):
    #     pass

    # 命名关键字形参(了解即可)
    def func(x, y=222, *args, n=777,m, **kwargs):  # m,n必须按照关键字实参的格式为其赋值
        print(x)  # 1
        print(y)  # 2
        print(args)  # (3,4,5)
        print("m===>", m)
        print("n===>", n)
        print(kwargs)
    func(1, 2, 3, 4, 5, n=88888,m=6666666, a=11, b=22, c=33)

二、函数对象
函数对象指的是函数可以被当成变量去使用

def foo():  # foo = 函数的内存地址
    print('from foo')

1 可以被赋值

f = foo
print(f is foo)
f()

2 可以当作参数传给一个函数

def bar(func):
    print(func)
    func()

bar(foo)

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

def bar(func):
    return func

res=bar(foo)
print(res)

4 可以当成容器类型的元素

l = [foo]

print(l)
l[0]()

示例:当我们的主函数是由多个其他函数组成,即我们需要使用许多的if来判断用户输入且调用对应的函数时候,可以使用这种容器的方法,使得代码量减少,同时,在面试时,若被问到如何减少if操作时,可使用字典替换

def login():
    print('登录功能......')


def withdraw():
    print('提现功能......')


def transfer():
    print('转账功能......')

def recharge():
    print('充值功能')

func_dic={
    "1": [login,"登录"],
    "2": [withdraw,"提现"],
    "3": [transfer,"转账"],
    "4": [recharge,"充值"]
}

func_dic["1"][0]()


while True:
    print("0    退出")
    for k in func_dic:
        print("%s    %s" %(k,func_dic[k][1]))

    choice = input("请输入你的指令编号: ").strip()
    if choice == "0":
        break
    if choice in func_dic:
        func_dic[choice][0]()
    else:
        print('输入的指令不存在')

三、函数嵌套
1 函数的嵌套调用

def bar():
    print('from bar')

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

foo()

案例:

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)
    print(res3)

max4(1,2,3,4)

2 函数的嵌套定义

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

# f2 = 函数的内存地址
def f2():
    print("from f2")
f1()

定义在函数内的函数特点是: 正常情况只能在函数体内调用

from math import pi

def circle(radius,mode=0):
    def perimiter(radius):
        return 2 * pi * radius

    def area(radius):
        return pi * (radius ** 2)

    if mode == 0:
        return perimiter(radius)
    elif mode == 1:
        return area(radius)

res1=circle(3,0)
res2=circle(3,1)
print(res1)
print(res2)
-------------------------
18.84955592153876
28.274333882308138


def func():
    x = 10
    print(x)
    def f2():
        print('from f2')
    f2()
func()
print(x)
---------------------------------
Traceback (most recent call last):
  File "xxx", line 122, in <module>
    print(x)
NameError: name 'x' is not defined
10
from f2

四、名称空间与作用域

'''
名称空间:就是存放名字的地方
    名(函数名、变量名等):存放在内存里
    值(变量值等):存放在内存里
    通过划分出各个名字空间,允许在不同的空间内,可以有相同的名字

    1、内置名称空间:存放内置的名字(python解释器启动时便定义好的)如 print、input、len
    生命周期:解释器启动则产生,解释器关闭则销毁 (python解释器在pyhton程序执行时运行,执行结束时结束)
    
    2、全局名称空间:存放的是顶级的名字

      生命周期:python程序运行时则产生,python程序结束则销毁

    3、局部名称空间:函数内的名字
        只有调用函数时,局部名字才产生,定义函数时,并不会产生,因为代码并未执行

    生命周期:调用函数时产生,函数调用结束则销毁

    访问 同名名字的优先级:局部>全局>内置
                         从当前位置往外查找

    名字的查找优先级:
        从当前位置往外查找,如果当前是在局部:局部名称空间->全局名称空间->内置名称空间
        从当前位置往外查找,如果当前是在全局:全局名称空间->内置名称空间
'''

1 内置名称空间: 存放的是内置的名字,如print\input\len
生命周期: 解释器启动则产生,解释器关闭则销毁

2 全局名称空间: 存放的是顶级的名字
生命周期: python程序运行时则产生,python程序结束则销毁

x = 10

def func():
    x = 111
    print(x)


if 1:
    y = 6666

3 局部名称空间:函数内的名字
生命周期: 调用函数时则产生,函数调用结束则销毁

名字的查找优先级:
从当前位置往外查找,如果当前是在局部:局部名称空间->全局名称空间->内置名称空间
从当前位置往外查找,如果当前是在全局:全局名称空间->内置名称空间

示范1:
def func():
    len = 222
    # print(len)

# len = 111

func()

print(len)

名称空间可以理解为一层套一层的关系,问题是嵌套关系是在函数定义阶段生成的,还是在函数调用阶段生成的?

x = 111

def foo():
    print(x)

def bar(f):
    x=222
    f()

bar(foo)

一个非常重要的结论:名称空间的嵌套关系是函数定义阶段(即扫描语法时)就固定死的,与函数的调用位置无关

x = 111
def func():
    print(x)
    x=2222

func()

练习
x=0
def f1():
    # x=1
    def f2():
        # x=2
        print(x)

    f2()

f1()


len = 111

def f1():
    len=2222

def f2():
    len=3333

f1()
f2()

全局范围/全局作用域:内置名称空间+全局名称空间
特点:全局存活,全局有效

局部范围/局部作用域:局部名称空间
特点:临时存活,局部有效

了解:
global(****) 在局部名称空间中指定某个变量为全局变量
nonlocal(***)

案例1

x = 10

def func(x): # x = 值10的内存地址
    # x = 值10的内存地址
    x = 20

func(x) # func(值10的内存地址)
print(x)

案例2

x = [11,22,33]

def func(x): # x = 列表[11,22,33]的内存地址
    # x = 列表[11,22,33]的内存地址
    # x=444444444444
    x[0] = 66666

func(x) # func(列表[11,22,33]的内存地址)
print(x)

案例3

x = [11,22,33]
def func():
    x[0] = 66666

func()
print(x)

案例4

x = 10
def func():
    global x
    x=22

func()
print(x)

案例5:nonlocal生命名字是来自于外层函数的(了解)

x = 10
def f1():
    x=111

    def f2():
        nonlocal x
        x=222

    f2()
    print(x)


f1()
print(x)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容