Day 16
今日内容概要
- *与**在实参中的作用
- 命名关键字参数(冷门了解)
- 名称空间
- 名字的查找顺序
- 名称空间的作用域
- 局部名称空间复杂情况
- global与nonlocal关键字
- 函数名的多种使用方式
今日内容详细
1.*与**在实参中的作用
*在实参前
eg:要求把以下列表、字符串、字典、元组里的所有数据当作一个一个的实参一次性传给函数
l1=[1,2,3,4,5]
s='cat'
d={'1':'jason','2':'18'}
t=(1,2,3)
def func(*args,**kwargs):
print(args)
print(kwargs)
func(*l1)# (1, 2, 3, 4, 5) {}
func(*s)#('c','a','t') {}
func(*d)#('1','2') {}
func(*t)#(1,2,3) {}
'一个*相当于把列表、字符串、字典等用for循环全部取出来,然后一次性给函数,变成元组的形式'#字典参与循环只有键参与
**在实参前(仅针对字典)
eg:把以下字典的键值对当作关键字实参一次性传给函数
d={'name':'jason','age':'18'}
def func(*args,**kwargs):
print(args)
print(kwargs)
func(**d)#() {'name': 'jason', 'age': '18'}
'两个**相当于把字典里的键值对变成关键字实参传给函数'
2.命名关键字参数(冷门知识)
形参在传实参的时候 必须要用关键字实参才可以
def func(a,b,*args,c):#参数必须要在*args后面
print(a,b,args,c)
func(1,2,3,4,c=5)#1 2 (3,4) 5 1和2分别给a和b 3和4是多余的位置实参给*args变成元组 命名关键字参数给c
def func(a,b,*args,c,**kwargs):#参数必须在**kwargs前面
print(a,b,args,c,kwargs)
func(1,2,3,4,c=5,name='a')#1 2 (3,4) 5 {'name':'a'} 1和2给a和b 3和4是多余的位置实参给*args变成元组 命名关键字参数给c name='a'关键字实参给**kwargs变成字典
3.名称空间
名称空间就是用来存放变量名与数据值之间绑定关系的地方
"""
name='张三'
在内存中申请一块空间存储张三,然后绑定给变量名name,变量名与数据值之间绑定的关系就会被存放在名称空间中,今后使用的名字都是由名称空间中的变量名与关系去内存中找相应的数据值
del name
删除的不是数据值,而是变量名和变量名与数据值之间绑定的关系 当引用计数为0时则会被垃圾回收机制回收
"""
名称空间的分类:
1)内置名称空间
python解释器运行时就会立刻创建的空间(一些内置的名字)
eg: len() print() input()..
2)全局名称空间
py文件运行代码过程中产生的名字就会存入该空间
普通代码里的变量名、分支循环结构里的变量名、定义函数的函数名、定义类的类名
3)局部名称空间
函数体代码运行过程中产生的名字存放该空间(函数定义阶段创建的名字)
名称空间的存活周期:
内置名称空间
解释器运行(创建) 解释器关闭(销毁)
全局名称空间
py文件执行(创建) py文件结束(销毁)
局部名称空间
函数体代码运行(创建) 函数体代码结束(销毁)
4.名字的查找顺序
当有一个名字在三个名称空间中都有 查找的是哪个?
eg:
len='全局len'
def func():
len='局部len'
func()
print(len)#结果是全局len
'查找名字之前要先看自己在哪个名称空间中'
1.当前在全局名称空间
全局名称空间 没有>>去内置名称空间找
2.当前在局部名称空间
局部名称空间 没有>>去全局名称空间找 没有>>去内置名称空间找
#名字的查找顺序默认情况下不能颠倒,只能局部>>全局>>内置
5.名称空间的作用域
1.内置名称空间
在程序任意位置都可以用
2.全局名称空间
在程序任意位置都可以用
3.局部名称空间
在各自的局部空间中用
6.局部名称空间复杂情况
1.各自局部名称空间默认情况下不能彼此共享名字
def func1():
name = '张三'
print(age)
def func2():
age = 18
print(name)
func1()#结果会报错 因为局部名称空间不互通
func2()#结果会报错 因为局部名称空间不互通
2.特殊情况:函数局部名称空间的嵌套
def func1(): #1
x = 2 #3
def func2(): #4
x=3 #6
def func3(): #7
x=4 #9
print(x) #10
func3() #8
func2() #5
func1() #2 结果为4 当函数嵌套调用时,一直打开到最内层的func3,则print(x)会从最内层往外查找 哪个最先有x就用哪个
'这里需要注意:当func3里的x=4如果在print(x)下面 就会报错,因为函数在定义阶段名字的查找顺序就已经固定好了,它知道要在func3里查找 但是由于x=4还没定义出来 所以会报错。除非把func3中的x=4去掉才会往外一层找x=3'
7.global与nonlocal关键字
global
"""
局部修改全局名称空间中不可变类型的数据需要用关键字global声明
局部修改全局名称空间中可变数据类型的数据(列表、字典..)不需要关键字声明
"""
【改不可变类型】
money = 999
def func():
global money#在局部名称空间中操作的是全局名称空间的money
money = 1000#由于定义了global 所以是把全局名称空间的money改为1000
print(money)
func()#1000
print(money)#1000 全局名称空间的999被改为了1000
————————————————————————————————————————————————————
【改可变类型】
l1 = [1,2,3]#1
def func():#2
l1.append(66)#5 给全局名称空间尾部加66
print(l1)#6
l1.append(77)#3 给全局名称空间尾部加77
func()#4 结果为[1,2,3,77,66]
print(l1)#7 结果为[1,2,3,77,66]
'当某个空间没有涉及什么=什么的时候,那它就没有产生新的值,而是改变已有的变量'
nonlocal
"""
从内层局部名称空间修改外层局部名称空间中不可变类型要用关键字nonlocal'
从内层局部名称空间修改外层局部名称空间中可变类型不用要关键字
"""
def func():
x=1
def func1():
nonlocal x#在局部名称空间中改外面局部空间的x值
x=999
func1()
print(x)#结果是999
func()
8.函数名的多种使用方式
1.函数名可以被用来多次赋值(函数名与变量名使用一致)
def func():
print('z')
name = func
name()#z 可以当作函数名使用
name1 = name
name1()#z 也可以当作函数名使用
2.函数名可以当作函数的实参
def func():
print('z')
def func1(a):
print(a)
a()#z 当a=func时 a()就可以调用func()函数内的值
func1(func)#把函数func变成func1的实参 相当于 a=func
3.函数名可以当作函数的返回值
def func():
print('z')
def index():
return func #return后可以跟函数名
res = index() #返回值需要一个变量名接收
print(res)
res()#z res就可以调用func()函数内的值
4.函数名可以当作容器类型(可以存放多个数据值的数据类型,列表、元组、字典..)里面的数据值
l1 = [1,2,3,4,func]
print(l1)
l1[-1]()
"""
其实就是增加函数名身上的引用计数 谁拿到这个值谁就可以加括号调用
"""
编程套路:《自助存取款机》
def login():
print('登录功能')
def check_account():
print('查看账户余额')
def transfer():
print('转账功能')
# 提前构造功能字典 函数名不要加括号
func_dict = {'1': login,'2': check_account,'3': transfer}
while True:
print("""
1.登录功能
2.查看余额
3.转账功能
""")
choice = input('输入指令:').strip()#获取用户指令,并去掉空格
if choice in func_dict:#判断如果指令在字典中则执行下列代码
a = func_dict.get(choice)#通过键拿对应字典的值并赋值给a
a()#a()就可以运行该函数体代码
else:#如果指令不在字典中则回复没该功能
print('没有该功能编号')