*与**在形参与实参中的应用,函数的对象,函数的嵌套,名称空间与作用域
一、*与**在形参与实参中的应用
1、可变长参数
可变长指的是参数的个数不固定
站在实参的角度,实参是用来为形参赋值的,如果实参的个数不固定,那么必须要有对应的形参能够接收溢出实参
2、在形参中用*与**
2.1 在形参名前加*:*会把溢出的位置实参存成元组,然后赋值其后的形参名
def func(x,*y): # y=(2,3,4)
print(x) print(y) func(1,2,3,4) #y打印出来(2,3,4) func(1) #y打印出来() func() # 报错,位置形参x必须被传值
2.2 在形参名前加**:**会把溢出的关键字实参存成字典,然后赋值其后的形参名
def func(x, **y): print(x) print(y) # {'a': 111, 'b': 222, 'c': 333}
func(1,a=111,b=222,c=333) func(a=111, b=222, x=1, c=333)
3、在实参中用*与**
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。3.1 在实参前加*:*会把其后的值打散成位置实参
nums=[1,2,3]
func(*nums) # func(1,2,3) #实参带*的,可以跟字典,打散取出来的是字典的key
3.2 在实参前加**:**会把其后的值打散关键字实参
dic = {'y': 111, 'z': 222, 'x': 333} func(**dic) # func(y=111,z=222,x=333) #实参带**的,只能跟字典,把字典打散
4、在形参与实参中混用*与**
ps:形参中带* **是汇总操作; 实参中带* **是打散/解压操作
def index(x,y,z,a,b,c): #变量名只能叫 x,y,z,a,b,c print("index===>",x,y,z,a,b,c) def wrapper(*args, **kwargs): # args=(1, 2, 3,) kwargs={"a":1,"b":2,"c":3} #形参中带* **是汇总操作
index(*args, **kwargs) # index(*(1, 2, 3,),**{"a":1,"b":2,"c":3}) #实参中带 * ** 是打散/解压操作
# 解压完后变成 index(1,2,3,c=3,b=2,a=1)
wrapper(1, 2, 3, a=111, b=222, c=333) #也可以a=2,b=3,c=1与位置参数传的值一样
5、命名关键字形参(**)
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,6666666) # func(1,2,3,4,5,m=6666666)
func(1, 2, 3, 4, 5, n=88888,m=6666666, a=11, b=22, c=33)
二、函数对象
函数对象指的是函数可以被当成变量去使用
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
def foo(): print('foo') def bar(): print('bar') dic={ 'foo':foo, 'bar':bar, } while True: choice=input('>>: ').strip() if choice in dic: dic[choice]()
#案例:实现用户登录转账提现充值功能
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 max2(x,y): if x > y: return x else: return y max(1,2) # 案例比较加难度:
def max4(a,b,c,d): res1 = max(a,b) res2 = max(res1,c) res3 = max(res2,d) #注意要用max比较的功能,需要直接用其本身,不要再将其赋值成max2啥的
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)
示例: def func(): x = 10
print(x) def f2(): print('from f2') f2() func() # print(x)#报错name 'x' is not defined
四、名称空间与作用域
1、 名称空间: 就是存放名字的地方
1.1 内置名称空间: 存放的是内置的名字,如print\input\len
生命周期: 解释器启动则产生,解释器关闭则销毁
1.2 全局名称空间: 存放的是顶级的名字
生命周期: python程序运行时则产生,python程序结束则销毁
1.3 局部名称空间:函数内的名字
生命周期: 调用函数时则产生,函数调用结束则销毁
2、名字的查找优先级:
从当前位置往外查找,如果当前是在局部:局部名称空间->全局名称空间->内置名称空间
从当前位置往外查找,如果当前是在全局:全局名称空间->内置名称空间
def func(): len = 222
# print(len)
# len = 111
func() print(len) #注意代码级别
3、结论:
(1)名称空间可以理解为一层套一层的关系,名称空间的嵌套关系是函数定义阶段(即扫描语法时)就固定死的,与函数的调用位置无关
#示范1 # x=0
def f1(): # x=1
def f2(): # x=2
print(x) f2() f1()
#示范2
len = 111
def f1(): len=2222
def f2(): len=3333 f1() f2()
(2)全局范围/全局作用域:内置名称空间+全局名称空间
特点:全局存活,全局有效
(3)局部范围/局部作用域:局部名称空间
特点:临时存活,局部有效
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__ locals 是函数内的名字空间,包括局部变量和形参 enclosing 外部嵌套函数的名字空间(闭包中常见) globals 全局变量,函数定义所在模块的名字空间 builtins 内置模块的名字空间
4、了解
global(****) #只能修改全局变量,在定义阶段已经弄好
nonlocal(***) #只能修改外层变量
#案例1
x = 1
def func(x): # x = 值10的内存地址
# x = 值10的内存地址
x = 20 func(x) # func(值10的内存地址)
print(x) # 1
#案例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) #[66666, 22, 33]
#案例3
x = [11,22,33] def func(): x[0] = 66666 func() print(x) #[66666, 22, 33]
#案例4
x = 10
def func(): global x x=22 func() print(x) # 22
# 案例5:nonlocal生命名字是来自于外层函数的(***)
x = 10
def f1(): x=111
def f2(): nonlocal x x=222 f2() print(x) # 222
f1() print(x) # 10
更多精彩