* 和 ** 分别在形参和实参中的用法讲解

形参

* 参数:

  • 函数接收任意长度的非关键字参数,系统将这些参数用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}

命名关键字参数(了解)

  • 需要形参传实参的时候必须按照关键字
    • 在形参 * args的后面
    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文件结束(销毁)
  • 局部名称空间:函数体代码运行(创建),函数体代码结束(销毁)

名字查找顺序

  1. 当前在全局名称空间
    • 全局名称空间 → 内置名称空间
  2. 当前在局部名称空间
    • 局部名称空间 → 全局名称空间 → 内置名称空间
  3. 名字的查找顺序默认情况下不能颠倒只能是:局部名称空间 → 全局名称空间 → 内置名称空间

名称空间的作用域

  1. 内置名称空间:在程序任意位置都可以使用(全局有效)
  2. 全局名称空间:在程序任意位置都可以使用(全局有效)
  3. 局部名称空间:在各自的局部空间可以使用(局部有效)

局部名称空间复杂情况

  1. 各自局部名称空间默认情况下不能彼此共享名字
def func1():
    name = 'jason'
    print(age)

def func2():
    age = 18
    print(name)

func1()
func2()
  1. 特殊情况
x = 1
def func1():
    x = 2
    def func2():
        x = 3
        def func3():
            print(x)  # 特例
            # x = 4
        func3()
    func2()
func1()
  1. 函数在定义阶段其实名字的查找顺序就已经固定死了
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()

函数名的多种使用方式

  1. 函数名也可以被用来多次赋值(函数名与变量名使用一致)
name = func
name()
name1 = name
name1()
  1. 函数名还可以当做函数的实参
def index(a):
    print(a)
    a()
index(123)
name = 'jason'
index(name)
index(func)
  1. 函数名还可以当做函数的返回值
def index():
    return func
res = index()
print(res)
res()
  1. 函数名还可以当做容器类型里面的数据值
l1 = [1, 2, 3, 4, func]
print(l1)
l1[-1]()
 posted on 2022-07-04 20:41  念白SAMA  阅读(50)  评论(0)    收藏  举报