Python动态变量及排列组合

"coding dayday"

Posted by Weitu on April 2, 2020

工作由偏模型转到了偏策略,代码写的较之前少,时有发生键盘跟不上自己的想法。离开代码的时间越久,越需要总结。

一、背景

经常,我们需要对未知数量的参数做处理,事先我们不知道要创建多少个变量来承接这些参数;或者说参数的数量过于巨大,假设为100个,我们如果显式的定义变量来承接参数,比较繁琐且代码不够优雅。这时,我们就希望有一种机制,它可以根据我们参数的数量,来适配相应数量的变量。

假如我们需要创建for嵌套循环,我们不知道有几层嵌套,或者嵌套的层数不固定,我们无法将其写死;这时候,我们需要借助动态变量来承接每一级for循环的列表,同时,我们需要对不同列表里的内容进行组合。

二、动态变量

  1. exec动态赋值
import random

# 使用exec执行表达式,生成动态变量并为其赋值;使用时,也需要在exec中执行
# 1. 定义变量并赋值
for i in range(3):
    exec("dynamic_var_{}={}".format(i, random.randint(1, 100)))

# 2.使用变量
for i in range(3): # 换行
    exec('print(dynamic_var_{})'.format(i))
for i in range(3): # 不换行
    exec('print(dynamic_var_{}, end=" ")'.format(i))
  1. 命名空间动态赋值

在Python的命名空间中,将变量名与值存储在字典中,可以通过locals(),globals()函数分别获取局部命名空间和全局命名空间。

dynamic_vars = locals()
# 1. 定义变量并赋值
for i in range(3):
    dynamic_vars["v_%d" %i] = random.randint(1, 100)
    
# 2.使用变量
for i in range(3):
    print(dynamic_vars["v_%d" %i])

for i in range(3):
    print(dynamic_vars.get(("v_%d" %i)), end=" ")

总结:个人以为使用命名空间动态赋值更易用,代码更优雅

三、排列组合

  1. 在一个列表里面排列组合,可以使用python的内置包 itertools
from itertools import combinations, permutations

lst = [1, 3, 6, 9]
print(list(combinations(lst, 3)))
print(list(permutations(lst, 3)))
  1. 但是,如果我们要在不同的列表里面,一次抽且仅抽一个数出来,组成序列(模拟嵌套for),显然上面是无法满足需要的,这也是本篇文章需要解决的最大问题。这里存在两个难点:
    • 事先不知道有几层for,根据传进来的字典确定,入参形如params_dict={“cnt_pboc_3d”:[1, 10, 2]}, 表示指标,指标下界、上界、步长。
    • 事先不知道每一层for,上下界及步长

      好吧,码了很多代码,最后还是不敌python的一条语句,可以使用官方函数完美解决,即计算list的笛卡尔积 【人生苦短,我用Python】

from itertools import product

print(len(list(product(["A1","A2","A3"],["B1","B2","B3"], ["C1", "C2"]))))
print(list(product(["A1","A2","A3"],["B1","B2","B3"], ["C1", "C2"])))

四、总结

函数 数学意义 解释
product 笛卡尔积 有放回抽样排列
permutations 排列 无放回抽样排列
combinations 组合,没有重复 无放回抽样组合
combinations_with_replacement 组合,有重复 有放回抽样组合

itertools官网