可变长参数,函数的对象,函数嵌套,名称空间和作用域

1.可变长参数

可变长参数:在调用函数时,参入的参数个数可以不固定。

调用函数时,传值的方式莫非两种,一种是位置实参,另一种是关键字实参,因此形参也必须的有两种解决方式,以此来分别接收溢出的位置实参(*)也关键字实参(**)

一.可变长形参之*

形参中的会将溢出的位置实参全部接收,然后存储元组的形式,然后把元组赋值给后的参数。需要注意的是:*后的参数名约定俗成为args。

def sum(*args):
    res = 0
    for sum_new in args:
        res += sum_new
    return res
res = sum(1,2,3,4,5)
print(res)   # 15

二 .可变长实参之*

实参中的会将后参数的值循环取出,达三成位置实参。以后但凡碰到实参中带的,他就是位置实参,应该马上打散成位置实参去看。

def func(a,b,*,c,d):
	print(a,b)
	print(c,d)

lst = [10,11]
''' *lst 相当于把列表中的每一个元素单独拿出来,扔到参数中进行赋值;'''
func(*lst,c=12,d=13) # func(10,11,c=12,d=13)

列二:
def func(x, y, z, *args):
    print(x, y, z, args)
func(1, *(1, 2), 3, 4)#1,1,2,(3,4)

三. 可变长实参之**

形参中的** 会将溢出的关键字实参全部接收,然后存储字典的形式,然后把字典赋值给** 后的参数。需要注意的是:**后的参数名约定俗成为kwargs。

def func(**kwargs):
    print(kwargs)
func(a=5)  #{"a":5}

四 .可变长实参之**

实参中的会将** 后参数的值循环取出,打散成关键字实参。以后但凡碰到实参中带**的,它就是关键字实参,应该马上打散成关键字实参去看。

def func(x,y,z,**kwargs):
    print(x,y,z,kwargs)
func(1,2,3,**{"a":1,"b":2})
#1 2 3 {'a': 1, 'b': 2}

列er:深
def func(a,b,*,c,d):
	print(a,b)
	print(c,d)
dic = {"c":12,"d":13}
''' **dic 相当于把字典当中每一个元素变成 c=12,d=13 的形式传入关键字实参 '''
func(10,11,**dic) #func(10,11,c=12,d=13)

五 .可变长参数的列题应用。

ndex(name ,age,hobby):
    print(f"name:{name},age:{age},hobby:{hobby}")
def guess(*args,**kwargs):
    print(f'args:{args}')
    print(f'kwargs:{kwargs}')
    index(*args,**kwargs)
guess(name="liangjing",age="20",hobby="购物,run,听音乐")
#args:()
#kwargs:{'name': 'liangjing', 'age': '20', 'hobby': '购物,run,听音乐'}
#name:liangjing,age:20,hobby:购物,run,听音乐

六. 关键字形参

现在有一个需求,函数的使用者必须按照关键字实参传。

def register(x, y, **kwargs):
    if 'name' not in kwargs or 'age' not in kwargs:
        print('用户名和年龄必须使用关键字的形式传值')
        return
    print(kwargs['name'])
    print(kwargs['age'])
register(1, 2, name='liangjing', age=20)
#liangjing
# 20

命名关键字形参:在函数定义阶段,*后面的参数都是命名关键字参数。

特点:在传值时,必须按照key=value的方式传值,并且key必须命名关键字参数的指定的参数名。

2.函数的对象

函数是第一类对象,即函数可以被当做数据处理。

一 . 函数对象的四大功能。

1.引用

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

# 函数对象 == 函数名  # 函数名()就是在调用,没有其他的意思

# 1. 引用
func = f1
print('f1:', f1)  #f1: <function f1 at 0x0000019E710BA1F8>  f1打印地址
print('func:', func) #func: <function f1 at 0x0000019E710BA1F8>

func()#  from f1

2.当作容器类元素

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

# 函数对象 == 函数名  # 函数名()就是在调用,没有其他的意思

# 1. 引用
lt = [f1, 1, 2, 3]
print('lt[0]', lt[0]) #lt[0] <function f1 at 0x000002628657A1F8>
print('f1', f1)#f1 <function f1 at 0x000002628657A1F8>
lt[0]()#form f1
  1. 当作函数参数
def f1():
    print('from f1')
def f2(f2_f1):
	print('f2_f1',f2_f1)
	f2_f1()
	f2(f1)
print('f1', f1)
#f2_f1 <function f1 at 0x000001A00C79A318>
#from f1
# f1 <function f1 at 0x000001A00C79A318>

  1. 当作函数的返回值
def f1():
    print('from f1')
def f2(f2_f1):
    return f2_f1
res = f2(f1)
print('res', res)  #res <function f1 at 0x000001D6E002A168>
print('f1', f1)  #f1 <function f1 at 0x000001D6E002A168>
res() #from f1

3.函数对象的练习。

def register():
    print('register')

def login():
    print('login')

def withdraw():
    print('wightdraw')

def shopping():
    print('shopping')

func_dict = {
    '1': register,
    '2': login,
    '3': withdraw,
    '4': shopping,
}

print('''
1 注册
2 登录
3 提现
4 购物
''')

while True:
    choice = input('请选择你需要的功能(输入q退出):')
    if choice == 'q':
        break
    func_dict[choice]()

4.函数嵌套。

一 . 函数的嵌套定义

#定义函数,只检测语法,不会执行代码
def f1():
    def f2():
        print('from f2')
    f2()

f2()  # NameError: name 'f2' is not defined(报错:没有定义f2)

定义后

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

f1() #from f2

现在有个需求,通过函数做一个九九乘法表。

#方法
# # 打印九九乘法表
# for i in range(1, 10):  # i控制的是行
#     for j in range(i):  # j控制的是列
#         print(f'{j+1}*{i}={(i)*(j+1)}', end=' ')
#
#     print()  # 打印换行
#
# '''
# i控制行,j控制列
# i = 1  for j in range(1) j = 0 + 1
# i = 2  for j in range(2) j = 0 + 1 j = 1 + 1
# i = 3  for j in range(3) j = 0 + 1 j = 1 +1 j = 2 + 1
# i = 4
# i = 5
##################################################################
# 函数的定义 
#def 函数名(等同于变量名)():
#     """对函数(工具)的描述信息"""
#     代码块
def chengfabiao():
    """描述的信息"""
    for i in range(1, 10):
        for j in range(1, i + 1):
            print("%d*%d=%2d " % (i, j, i * j), end="")
        print()
        
# 函数的调用
chengfabiao()
chengfabiao()
chengfabiao()
#结果:
1*1= 1 
2*1= 2 2*2= 4 
3*1= 3 3*2= 6 3*3= 9 
4*1= 4 4*2= 8 4*3=12 4*4=16 
5*1= 5 5*2=10 5*3=15 5*4=20 5*5=25 
6*1= 6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 
7*1= 7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 
8*1= 8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 
9*1= 9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81


二 .函数的嵌套调用。

def max2(x, y):
    if x > y:
        return x  #return是一个返回值,默认返回较大的数。
    else:
        return y

def max4(a, b, c, d):
    res1 = max2(a, b) 
#调用值max4拿到res1中,这时a=1,b=2带max2中进行比较x=1,y=2,此时y大,res1=2(b),将b(b=2)带入res2进行比较,依次比较下去。                 
    res2 = max2(res1, c)
    res3 = max2(res2, d)
    return res3

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

列:

# 定义函数,只检测语法,不会执行代码
def f1():
    print('from f1')

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

res = f1()#打印的是外部的值 from f1

           # ***:函数内部定义的函数,外部不能用

5.名称空间和作用域

变量名/函数名 --》 名称 --》=专门存储名称的

名称空间(name spaces):在内存管理那一章节时,我们曾说到变量的创建其实就是在内存中开辟了一个新的空间。但是我们一直在回避变量名的存储,其实在内存中有一块内存存储变量名与变量间的绑定关系的空间,而这个空间称为名称空间。(存储了内置方法的名称)

一. 内置名称空间

内置名称空间:存放Pyhton解释器自带的名字,如int、float、len

生命周期:在解释器启动时生效,在解释器关闭时失效

二.全局名称空间(执行文件代码的时候才会有全局)

全局名称空间:除了内置和局部的名字之外,其余都存放在全局名称空间,如下面代码中的x、func、l、z

生命周期:在文件执行时生效,在文件执行结束后失效

x = 1

def func():
    pass

l = [1, 2]

if 3 > 2:
    if 4 > 3:
        z = 3

三 . 局部名称空间 (函数调用的时候才会有局部)

局部名称空间:用于存放函数调用期间函数体产生的名字,如下面代码的f2

生命周期:在文件执行时函数调用期间时生效,在函数执行结束后失效。

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

f1() 

四. 加载顺序

由于.py文件是由Python解释器打开的,因此一定是在Python解释器中的内置名称空间加载结束后,文件才开始打开,这个时候才会产生全局名称空间,但文件内有某一个函数被调用的时候,才会开始产生局部名称空间,因此名称空间的加载顺序为:内置--》全局--》局部。

五 .搜索顺序:先从当前所在位置寻找,找不到再按照这种顺序,不会逆着方向寻找 局部 --》 全局 --》 内置 --》 报错

二 . 作用域

一.作用域:域指的是区域,作用域即作用的区域。

二 .全局作用域

全局作用域:全局有效,全局存活,包含内置名称空间和全局名称空间。

# 全局作用域
x = 1

def bar():
    print(x)

bar()  #1

三 .局部作用域

局部作用域:局部有小,临时存储,只包含局部名称空间。

# 局部作用域
def f1():
    def f2():
        def f3():
            print(x)
        x = 2
        f3()
    f2()

f1() #2

四. 注意点需要注意的是:作用域关系在函数定义阶段就固定死了,与函数的调用无关。

x = 1

def f1():  # 定义阶段x=1
    print(x)

def f2():
    x = 2
    f1()

f2()#1   与函数的调用无关

五. 函数对象+作用域应用

# 作用域应用
def f1():
    def inner():
        print('from inner')
    return inner

f = f1()  # 把局部定义的函数放在全局之中

def bar():
    f()

bar()  #from inner

六 . global关键

修改全局作用域中的变量。

七. nonlocal 关键字

修改局部作用域中的变量。

八 .注意点

3.3 注意点

  1. 在局部想要修改全局的可变类型,不需要任何声明,可以直接修改。
  2. 在局部如果想要修改全局的不可变类型,需要借助global声明,声明为全局的变量,即可直接修改。
lis = []

def f1():
    lis.append(1)

print(f"调用函数前: {lis}")
f1()
print(f"调用函数后: {lis}")
#调用函数前: []
#调用函数后: [1]

原文地址:https://www.cnblogs.com/WQ577098649/p/11559820.html