我怎样才能使这个 If Loop 成为对 Python 有效的字典

How can I make this If Loop into a dictionary valid for Python

我正在做一个有趣的小 python 项目,我一直在尝试将我的 If 循环改编成字典,但我只是不确定如何实现这个功能,因为我需要多个条件已测试。

我有六个布尔值,(bool1-bool6) 显然可以是 T 或 F,并且 我需要测试这些布尔值的所有可能组合,以便我可以告诉我的程序在哪里绘制图像。

有 64 种可能的组合。

为了简单起见,我们可以使用 3 个布尔值来完成此操作,3 个布尔值有 8 种可能的组合。

如果我们想象1=true和0=false,那么可能的组合可以这样表示。

000
001
010
011
100
101
110
111

表示这个的 if 循环是,

if (bool1==false and bool2==false and bool3==false)
      do stuff
elif (bool1==false and bool2==false and bool3==true)
     do stuff
elif (bool1==false and bool2==true and bool3==false)
     do stuff

and so on...

请除非你能找到一种方法来简化这个过程,(理解我需要检查布尔值的所有可能组合),否则没有必要批评我的问题。我只是不确定如何从这里取得进展,非常感谢您的帮助。

我已经编写了一个 64 语句的 If Loop,并且目前正在研究该解决方案,尽管我自己和我确信我的 cpu 更喜欢更快的方法。

这是使用整数的位表示的完美示例

你有六个布尔变量 bool1 到 bool6。

想要你想要的有点像下面的例子:

101101

其中最左边的位代表bool6,最右边的位代表bool1。 所以你得到顺序 bool6, bool5, bool4, ..., bool1.

现在您为变量分配状态,由这些布尔变量表示:

state = bool6 << 5
state = state ^ (bool5 << 4)
state = state ^ (bool4 << 3)
state = state ^ (bool3 << 2)
state = state ^ (bool2 << 1)
state = state ^ (bool1)

你找到 << here

的解释

现在发生的事情是,您定义了一个新的整数变量,由不同的布尔值表示。

使用位表示

根据您的进一步 do_something 实现,您可以像这样定义方法参数:

cases = {
    0b000011 : "drawing parameter",
    0b001011 : "drawing parameter",
    0b111000 : "another drawing parameter",
}

其中,字典键是您从 000000111111

的位

此外,您可以检查每个案例是否有定义的参数:

for n in range(1<<6):
    if not n in cases:
       raise LookupError('cases do not contain index %d' % n)

所以,稍后,您可以像下面这样使用这些位表示。

for c in cases:
    if state == c: # if the checked case is equal to the state, then use the parameters
       parameters = cases[c]
       do_something(parameters)

对于 6 个布尔值,有 2^6 种组合直接对应从 02^6-1 的数字中的位。如果需要为单个函数调用定义特殊参数,可以通过使用参数列表或字典来解决这个问题,然后使用每个参数调用该函数:

cases = {
    0b000000: ((arg1a, arg2y), {'key1': kwarg1, 'key2': kwarg2}),
    0b000001: ((arg1b, arg2x), {'key23': kwarg23, 'key7': kwarg7}),
    # ...
    0b111111: ((arg1a, arg2z), {'key4': kwarg4, 'key2': kwarg2}),
}

for n, (args, kwargs) in cases.items():
    print("Test case {:d} ({:#08b}):".format(n,n))
    test_fun(*args, **kwargs)

如果不需要关键字参数,可以轻松简化。

如果你需要做更具体的事情,你可以在字典中使用 lambdas 而不是参数集:

cases = {
    0b000000: lambda: test_fun(1,2, foo='bar'),
    0b000001: lambda: test_fun(3,2, moo='bar'),
    # ...
    0b111111: lambda: test_fun(8,3, foo='bar'),
    }

for n, fun in cases.items():
    print("Test case {:d} ({:#08b}):".format(n,n))
    fun()

您还可以将这些字典变成列表,将字典索引变成注释:

cases = [
    # 0b000000
    ((arg1a, arg2y), {'key1': kwarg1, 'key2': kwarg2}),
    # 0b000001
    ((arg1b, arg2x), {'key23': kwarg23, 'key7': kwarg7}),
    # ...
    # 0b111111
    ((arg1a, arg2z), {'key4': kwarg4, 'key2': kwarg2}),
]

for n, (args, kwargs) in enumerate(cases):
    print("Test case {:d} ({:#08b}):".format(n,n))
    test_fun(*args, **kwargs)

在所有情况下,我都会确保在 cases 的定义之后直接放置一致性检查,例如

# for the `cases` dictionary
for n in range(1<<6):
    if not n in cases:
        raise LookupError("dict variable cases does not contain %d" % n)

# for the `cases` list
assert(len(cases) == (1<<6))

如果您可以轻松地从索引号中机器导出参数集,则可以避免定义完整的测试用例列表或字典,而只需即时计算参数值:

for n in range(1<<6):
    param1 = 23
    if (n & (1<<0)):
        param1 = 42
    # ...
    param6 = bool(n & (1<<5))

    # ...
    test_fun(param1, ..., param6)

或者您可以将参数生成逻辑放入生成器函数中,可选择将 yield 语句中的元组表达式替换为(可能 reversed()list.

def all_bool_tuples_from_bits(n):
    for k in range(1<<n):
        yield (bool(k&(1<<i)) for i in range(n))

print("Run test_fun with the arguments")
for args in all_bool_tuples_from_bits(6):
    test_fun(*args)

print("Run test_fun with the arguments in explicit variables")
for p0, p1, p2, p3, p4, p5 in all_bool_tuples_from_bits(6):
    test_fun(p0, p1, p2, p3, p4, p5)

print("Run test_fun with the arguments while numbering the test cases")
for n, args in enumerate(all_bool_tuples_from_bits(6)):
    print("Test case {:d} ({:#08b}):".format(n,n))
    test_fun(*args)

我希望这能给你一些工作的想法。

关于 CPU 用法,我完全不担心只有 64 个不同的测试用例,每个测试用例都会生成一个 PDF 文件,这肯定比迭代 64 个测试用例更加 CPU 密集永远可以。

真正担心的是您可能会忘记在那个巨大的 if elif elif elif 结构中列出一个案例,而您自己却没有注意到这一点。所以我想使用代码让计算机确保确实检查了每个组合。对于只有 6 个布尔参数,我会使用生成器。

整数到二进制的方法很聪明,但不能一概而论。有一种更简单的方法也可以推广到布尔以外的数据类型:

import itertools
for i in itertools.product((0, 1,), repeat=3):
    ... stuff ...

这将 return 个元组,例如 (0, 0, 0), (0, 0, 1) ... (1, 1, 1)

您可以将未命名的第一个参数更改为任何可迭代的 - xrange()、集合、数组等 - 并将 repeat 参数更改为所需的长度。适用于任何数据类型。