我怎样才能使这个 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",
}
其中,字典键是您从 000000
到 111111
的位
此外,您可以检查每个案例是否有定义的参数:
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 种组合直接对应从 0
到 2^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
参数更改为所需的长度。适用于任何数据类型。
我正在做一个有趣的小 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",
}
其中,字典键是您从 000000
到 111111
此外,您可以检查每个案例是否有定义的参数:
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 种组合直接对应从 0
到 2^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
参数更改为所需的长度。适用于任何数据类型。