星号(*)特殊用法

一、序列和可迭代对象拆包

1. 调用函数时在参数前面加上一个*,利用拆包

divmod(20, 8) #输出:(2, 4)
t = (20, 8)
divmod(*t) #输出:(2, 4)

2. 使用*获取余下的项

定义函数时可以使用*args捕获余下的任意数量的参数,这是Python的一个经典特性。

a, b,*rest = range(5)
a, b, rest  #输出: (0, 1, [2, 3, 4])

a, b,*rest = range(3)
a, b, rest  #输出: (0, 1, [2])

a, b,*rest = range(2)
a, b, rest  #输出: (0, 1, [])

并行赋值时,*前缀只能应用到一个变量上,不过可以是任何位置上的变量。

a, *body, c, d = range(5)
a, b, rest   #输出: (0, [1, 2], 3, 4)

*head, b, c, d = range(5)
head, b, c, d   #输出:  ([0, 1], 2, 3, 4)

二、在函数调用和序列字面量中使用*拆包

1. 在函数调用中可以多次使用*

def fun(a, b, c, d, *rest):
    return a, b, c, d, rest

fun(*[1, 2], 3, *range(4, 7))   #输出:(1, 2, 3, 4, (5, 6))

2. 定义列表、元组或集合字面量时,也可以使用*

*range(4), 4    #输出:(0, 1, 2, 3, 4)
[*range(4), 4]  #输出:[0, 1, 2, 3, 4]
{*range(4), 4, *(5, 6, 7)}   #输出:{0, 1, 2, 3, 4, 5, 6, 7}

3. 映射拆包

首先,调用函数时,不止一个参数可以使用**。但是,所有键都要是字符串,而且在所有参数中是唯一的(因为关键字参数不可重复)。

def dump(**kwargs):
    return kwargs

dump(**{'x': 1}, 'y': 2, **{'z': 3})   #输出:{'x': 1, 'y': 2, 'z': 3}

其次,**可在dict字面量中使用,同样可以多次使用。

{'a': 0,**{'x': 1}, 'y': 2, **{'z': 3, 'x': 4}}  #输出:{'a':0, 'x': 4, 'y': 2, 'z': 3}

三、强制关键字参数

在函数定义中,单独使用 * 可以强制后续参数必须通过关键字传入。

def greet(name, *, message="Hello"):
    print(f"{message}, {name}!")

greet("Alice")                # 输出 "Hello, Alice!"
greet("Bob", message="Hi")    # 正确,输出 "Hi, Bob!"
greet("Charlie", "Hey")       # 报错:位置参数不允许

四、match/case语句中使用“*_”

*_ 匹配任意数量的项,而且不绑定变量。

match record:
'''
匹配任何以字符串开头,
以嵌套两个浮点数的序列结尾的序列。
'''
    case [str(name), *_, (float(lat), float(lon))]:  
        pass

总结

场景 示例 说明
乘法/重复 3 * 4 或 [1,2] * 3 数值乘法或序列重复
函数参数(*args) def func(*args): … 接收任意位置参数
解包参数 func(*[1,2,3]) 将列表解包为位置参数
强制关键字参数 def func(a, *, b): … b 必须通过关键字传入
扩展解包 a, *b = [1,2,3] 将剩余元素赋值给 b(列表)
通配符导入 from math import * 导入模块所有公共名称
映射拆包 def dump(**kwargs): dump(**{‘x’: 1}, ‘y’: 2, **{‘z’: 3}) **可在dict字面量中使用,同样可以多次使用。
match/case语句中使用 *_ case [str(name), *_, (float(lat), float(lon))]: 匹配任何以字符串开头,以嵌套两个浮点数的序列结尾的序列。

根据具体场景选择合适用法,注意避免滥用通配符导入和过度依赖可变参数以提高代码可读性

你可能感兴趣的:(Python学习笔记,python)