咨询Python代码中itertools.product()与*解包符的使用逻辑
代码逻辑分步解释
首先明确需求:需要对字典每个key对应的列表做笛卡尔积,每个组合从不同key的列表各取一个元素,拼接输出。示例中的字典d ={'1':['a','b'], '2':['c','d']}的预期输出为ac、ad、bc、bd。
1. 列表推导式的运行逻辑
代码中[d[k] for k in sorted(d.keys())]是列表推导式,执行步骤如下:
- 第一步
sorted(d.keys()):将字典的所有key按升序排序,示例中得到的结果是['1', '2'] - 第二步遍历排序后的key,取出每个key对应的列表:先取
d['1']得到['a','b'],再取d['2']得到['c','d'] - 最终列表推导式的输出结果是
[['a','b'], ['c','d']]
2. *符号的作用
这里的*是Python的可迭代对象解包运算符,作用是把列表/元组中的每一个元素拆成独立的位置参数传给函数。itertools.product函数本身要求传入多个独立的可迭代对象作为参数,比如要对['a','b']和['c','d']做笛卡尔积,正确的调用写法是itertools.product(['a','b'], ['c','d'])。
如果不加*直接把列表[['a','b'], ['c','d']]传给product,相当于只传了1个参数,函数会把这个列表当成单个可迭代对象处理,得到的结果不是我们要的字母组合。加了*之后,就等价于把列表里的两个子列表拆成两个独立参数传入,完全符合product的参数要求。
3. 按排序后的key取值的原因
作者这么写主要是两个原因:
- 保证顺序稳定:Python3.7之前的版本字典是无序的,直接调用
d.values()取到的列表顺序可能和key的顺序不一致,提前对key做排序再取值,能保证每次传入product的列表顺序是固定的,最终生成的组合顺序不会随机变化。 - 扩展性强:如果后续字典新增更多key和对应的列表(比如加
'3':['e','f']),这段代码不需要做任何修改,自动会把新增的列表也加入笛卡尔积的计算,不需要手动改product的传参。
简化验证示例
你可以跑下面的简化代码观察差异,更快理解逻辑:
import itertools d ={'1':['a','b'], '2':['c','d']} # 看列表推导式的结果 print("列表推导式结果:", [d[k] for k in sorted(d.keys())]) # 输出:[['a', 'b'], ['c', 'd']] # 不加*的错误用法输出 print("不加*的输出:") for i in itertools.product([d[k] for k in sorted(d.keys())]): print(i) # 输出是两个单独的列表,不是字母组合: # (['a', 'b'],) # (['c', 'd'],) # 加*的正确用法输出 print("加*的输出:") for i in itertools.product(*[d[k] for k in sorted(d.keys())]): print(''.join(i)) # 输出符合预期的字母组合: # ac # ad # bc # bd
内容的提问来源于stack exchange,提问作者user12170926
相关产品推荐
相关产品推荐

