作为Mathematica用户,我喜欢自动“在列表上进行线程化”的函数(正如Mathematica所称的那样 - 请参阅http://reference.wolfram.com/mathematica/ref/Listable.html)。这意味着如果函数被赋予列表而不是单个值,它会自动使用每个列表条目作为参数并返回结果列表 - 例如
myfunc([1,2,3,4]) -> [myfunc(1),myfunc(2),myfunc(3),myfunc(4)]
我在Python中实现了这个原则:
def myfunc(x):
if isinstance(x,list):
return [myfunc(thisx) for thisx in x]
#rest of the function
这是一个很好的方法吗?你能想到这个实施或整体战略的任何缺点吗?
答案 0 :(得分:7)
如果这是你要在很多函数中做的事情,你可以使用Python装饰器。这是一个简单但有用的。
def threads_over_lists(fn):
def wrapped(x, *args, **kwargs):
if isinstance(x, list):
return [fn(e, *args, **kwargs) for e in x]
return fn(x, *args, **kwargs)
return wrapped
这样,只需在函数前添加行@threads_over_lists
就可以使其表现出来。例如:
@threads_over_lists
def add_1(val):
return val + 1
print add_1(10)
print add_1([10, 15, 20])
# if there are multiple arguments, threads only over the first element,
# keeping others the same
@threads_over_lists
def add_2_numbers(x, y):
return x + y
print add_2_numbers(1, 10)
print add_2_numbers([1, 2, 3], 10)
您还应该考虑是否希望它仅在列表上进行矢量化,或者也可以在其他可迭代对象(如元组和生成器)上进行矢量化。 This是一个有用的StackOverflow问题,用于确定它。但请注意 - 字符串是可迭代的,但您可能不希望函数对其中的每个字符进行操作。
答案 1 :(得分:3)
这是一个很好的方法。 但是,您必须为您编写的每个函数执行此操作。 为避免这种情况,您可以像这样使用decorator:
def threads(fun):
def wrapper(element_or_list):
if isinstance(element_or_list, list):
return [fun(element) for element in element_or_list]
else:
return fun(element_or_list)
return wrapper
@threads
def plusone(e):
return e + 1
print(plusone(1))
print(plusone([1, 2, 3]))