* 和 ** 分别在形参和实参中的用法讲解
形参
* 参数:
- 函数接收任意长度的非关键字参数,系统将这些参数用tuple元组组合起来表示
def func(*args):
print(args)
func('a', 'b', 'c', 'd') # ('a', 'b', 'c', 'd')
** 参数:
- 函数接收任意长度的关键字参数,系统将这些参数用dict字典组合起来表示
def func(*args):
print(args)
func(a=1, b=2, c=3) # {'a': 1, 'b': 2, 'c': 3}
混合使用
def func(*args, **kwargs):
print(args, kwargs)
print(a=1, b=2, c=3, 5, 6) # 报错
实参
* 参数:
- 实参中的*后面跟的是可迭代对象,获取的是可迭代对象的 key,此时形参为位置参数或可变参数都可以
def func(*args):
print(args)
l1 = [1, 2, 3, 4]
func(*l1) # (1, 2, 3, 4)
- 除了list, str, tuple等,还可以用dict作为实参,获取的是dict中的key值
def func(*args):
print(args)
d1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
func(*d1) # ('a', 'b', 'c', 'd')
** 参数:
- 实参中的 ** 后面跟的是可迭代映射,获取的是可迭代映射的 value。此时,当形参为位置参数时,获取的是可迭代映射的value,当形参为关键字参数时,获取的是dict
def func(* args, **kwargs):
print(args)
print(kwargs)
d1 = {'username': 'jason', 'pwd': 123}
func(**d1) # () {'username': 'jason', 'pwd': 123}
func(username='jason', pwd=123) # () {'username': 'jason', 'pwd': 123}
命名关键字参数(了解)
- 需要形参传实参的时候必须按照关键字
def func(a, b, *args, c):
print(a, b, args, c)
func(1,2,3,4,5,6,7) # 报错
func(1, 2, 3, 4, 5, 6, c=666)
- 如果形参中还有** kwargs,那必须在它的前面
def func(a,b,*args,c,**kwargs):
pass
func(1,2,3,4,5,6,c=123,name='jason')
名称空间
定义
- 就是用来存放变量名与数据值之间绑定关系的地方
- name = 'jason':在内存中申请一块内存空间存储jason,然后绑定变量名name
- 变量名name与值jason的绑定关系就会被存储到名称空间中,之后使用名字都是去名称空间中查找并锁定对应的数据值
- del name
- 删除的不是数据值,而是变量名以及变量名与数据值之间的绑定关系
名称空间的分类
- 内置名称空间:python解释器运行就会立刻创建的空间
- 全局名称空间:py文件运行代码过程中产生的名字都会存入该空间
- 普通代码里的变量名
- 分支结构里的变量名
- 循环结构里的变量名
- 定义函数的函数名
- 定义类的类名
- 局部名称空间:函数体代码运行过程中产生的名字都会存入该空间
名称空间的存活周期
- 内置名称空间:解释器运行(创建),解释器关闭(销毁)
- 全局名称空间:py文件运行(创建),py文件结束(销毁)
- 局部名称空间:函数体代码运行(创建),函数体代码结束(销毁)
名字查找顺序
- 当前在全局名称空间
- 当前在局部名称空间
- 名字的查找顺序默认情况下不能颠倒只能是:局部名称空间 → 全局名称空间 → 内置名称空间
名称空间的作用域
- 内置名称空间:在程序任意位置都可以使用(全局有效)
- 全局名称空间:在程序任意位置都可以使用(全局有效)
- 局部名称空间:在各自的局部空间可以使用(局部有效)
局部名称空间复杂情况
- 各自局部名称空间默认情况下不能彼此共享名字
def func1():
name = 'jason'
print(age)
def func2():
age = 18
print(name)
func1()
func2()
- 特殊情况
x = 1
def func1():
x = 2
def func2():
x = 3
def func3():
print(x) # 特例
# x = 4
func3()
func2()
func1()
- 函数在定义阶段其实名字的查找顺序就已经固定死了
name = 'jason'
def func():
print(name) # 报错
name = 'jasonNB'
func()
global与nonlocal关键字
- 正常情况下,局部名称空间里面出现新的名字会在局部名称空间中存储,但是有时候需要在局部名称空间中修改全局名称空间的名字
money = 999
def func():
money = 1000
print(money) # 1000
func()
print(money) # 999
def func():
global money # 声明 局部名称空间中的money操作的是全局的money
money = 1000
print(money) # 1000
func()
print(money) # 1000
- 局部修改全局名称空间中不可变类型的数据,需要使用关键字global声明,如果是可变类型,则无需关键字声明
l1 = [1, 2, 3, 4, 5]
s = '$jason$'
def func():
s = 'jason'
res = s.strip('$')
l1.append(113123)
l1.append(666)
func()
print(l1) # [1, 2, 3, 4, 5, 113123, 666]
def func():
global s
s = 'jason'
res = s.strip('$')
l1.append(113123)
l1.append(666)
func()
print(l1) # [1, 2, 3, 4, 5, 113123, 666]
- nonlocal 在内存局部名称空间修改外层局部名称空间中的不可变类型
def func1():
x = 1
l1 = [1,2]
def func2():
# nonlocal x
x = 999
l1.append(666)
func2()
print(x) # 1
print(l1) # [1, 2, 666]
func1()
def func1():
x = 1
l1 = [1,2]
def func2():
nonlocal x
x = 999
l1.append(666)
func2()
print(x) # 999
print(l1) # [1, 2, 666]
func1()
函数名的多种使用方式
- 函数名也可以被用来多次赋值(函数名与变量名使用一致)
name = func
name()
name1 = name
name1()
- 函数名还可以当做函数的实参
def index(a):
print(a)
a()
index(123)
name = 'jason'
index(name)
index(func)
- 函数名还可以当做函数的返回值
def index():
return func
res = index()
print(res)
res()
- 函数名还可以当做容器类型里面的数据值
l1 = [1, 2, 3, 4, func]
print(l1)
l1[-1]()