我只是想知道pythonic代码如何解决这个问题:
假设你有一个功能:
def do_stuff(a=True, b=True, c=True, d=True):
在该函数中你想构造相应的对象:
elements = []
if a:
elements.append(A())
if b:
elements.append(B())
if c:
elements.append(C())
if d:
elements.append(D())
有没有更好的方法来编写这段代码?如果没有,可选参数不是“走的路”?
答案 0 :(得分:1)
这个怎么样?
elements = [X() for x, X in ((a, A), (b, B), (c, C), (d, D)) if x]
但是你的整个方法看起来很奇怪。也许你不应该有这样的论点。但是不知道你真正需要什么......
答案 1 :(得分:1)
您可以使用itertools.compress
:
from itertools import compress
def do_stuff(a=True, b=True, c=True, d=True):
elements = [val() for val in compress([A, B, C, D], [a,b,c,d])]
答案 2 :(得分:1)
有没有更好的方法来编写这段代码?
老实说,在我看来没有。你可以做一个聪明的黑客并使用它,但编写好的代码的目的是使其清晰易读,易于理解。除了你现在所拥有的以外,我认为所有其他方法都不符合要求。
当然看起来相当冗长,但最好是有一个冗长而不是不必要的复杂性。有时,显而易见的方法是最惯用,最强大,最干净,更“pythonic”的解决方案。在这种情况下,我认为最好做KISS。
但是,这还取决于您如何将参数传递给函数。你现在在做什么似乎有点奇怪。传入列表或字典可能更自然。
答案 3 :(得分:0)
这是一种相当干净的方式(也是可扩展的)方式:
class A: pass
class B: pass
class C: pass
class D: pass
def do_stuff(a=True, b=True, c=True, d=True):
classes, args = (A, B, C, D), (a, b, c, d)
elements = [classes[i]() for (i, arg) in enumerate(args) if arg]
# Show results.
print(list('class {} obj'.format(element.__class__.__name__) for element in elements))
do_stuff(1,1,1,1) # -> ['class A obj', 'class B obj', 'class C obj', 'class D obj']
do_stuff(0,1,1,0) # -> ['class B obj', 'class C obj']
do_stuff() # -> ['class A obj', 'class B obj', 'class C obj', 'class D obj']
do_stuff(0,0) # -> ['class C obj', 'class D obj']
do_stuff(b=False) # -> ['class A obj', 'class C obj', 'class D obj']
注意我使用0
和1
代替False
和True
,因为Python会将它们视为相同(它会考虑"真实性"非布尔值的值是否为0
或空容器,具体取决于其类型)。
答案 4 :(得分:0)
您有许多需要根据条件调用的对象,if
语句的重复是需要避免的:
objs = {True:A, True:B, True:C ,...}
def do_stuff(objs):
return [obj() for key, obj in objs.items() if key]
无论这些可调用对象现在做什么,你只需调用它们,它们返回的任何内容都会被收集并保存在do_stuff
返回的列表中。现在,未来扩展更容易,只需从objs
字典中删除不需要的对象,或将其键设置为False
,或者将其设置为布尔值为False
的任何对象。