映射每个元素的功能?

map with function for each element?

我经常像这样处理元组的单个元素:

size, duration, name = some_external_function()
size = int(size)
duration = float(duration)
name = name.strip().lower()

如果 some_external_function 会 return 一些相同类型的元组,我可以使用 map 来获得(更实用的)封闭表达式:

size, duration, name = map(magic, some_external_function())

是否有类似 元素明智 map 的东西?我可以 运行 像这样:

size, duration, name = map2((int, float, strip), some_external_function())

更新:我知道我可以将理解与 zip 一起使用,例如

size, duration, name = [f(v) for f, v in zip(
   (int, float, str.strip), some_external_function())]

-- 我正在寻找 'pythonic'(最佳:内置)解决方案!

致 Python 开发人员

(size)int, (duration)float, (name)str.strip = some_external_function()

? 如果我在任何即将推出的 Python 版本中看到这个,我会送你一杯啤酒 :)

地图在这里并不适用。当您想对列表的所有元素应用一个简单的函数时,它会派上用场,例如 map(float, list_ints)

没有一个明确的内置函数可以执行此操作。但是,一种简化方法并避免 n 单独调用要应用的函数的方法可能是定义一个包含函数的可迭代对象,并将它们应用于返回的 非解压 来自生成器理解函数的元组,然后 然后 解压它们:

funcs = int, float, lambda x: x.strip().lower()
t = 1., 2, 'Some String  ' # example returned tuple

size, duration, name = (f(i) for f,i in zip(funcs, t))

或者更干净一点:

def transform(t, funcs):
    return (f(i) for f,i in zip(funcs, t))

size, duration, name = transform(t, funcs)

size
# 1
duration
# 2.0
name
# 'some string'
class SomeExternalData:
    def __init__(self, size: int, duration: float, name: str):
        self.size = size
        self.duration = duration
        self.name = name.strip().lower()

    @classmethod
    def from_strings(cls, size, duration, name):
        return cls(int(size), float(duration), name)


data = SomeExternalData.from_strings(*some_external_function())

它远非单行,但它是 IMO 解决此问题的最具声明性、可读性、可重用性和可维护性的方法。 模型 您的数据明确而不是临时处理个别值。

很简单:使用函数和args unpacking...

def transform(size, duration, name):
    return int(size), float(duration), name.strip().lower()

# if you don't know what the `*` does then follow the link above...    
size, name, duration = transform(*some_external_function())

非常简单,完全可读和可测试。

据我所知,没有内置的解决方案,所以我们可以自己编写通用函数,然后再使用它

def map2(functions, arguments):  # or some other name
    return (function(argument) for function, argument in zip(functions, arguments))  # we can also return `tuple` here for example

可能的问题可能是参数的数量可能少于函数的数量,反之亦然,但在您的情况下,这应该不是问题。 之后

size, duration, name = map2((int, float, str.strip), some_external_function())

我们可以 functools.partial 更进一步,给我们的 "transformer" 起个名字,比如

from functools import partial
...
transform = partial(map2, (int, float, str.strip))

并在其他地方重复使用。

基于 Bruno 的变换,我认为这是对问题的最佳答案,我想看看我是否可以制作一个通用的变换函数,它不需要一组硬编码的格式化程序,但可以采用任意数量的元素,给定匹配数量的格式化程序。

(这实在是太过分了,除非你需要大量这样的魔法映射器或者你需要动态生成它们。)

在这里,我使用 Python 3.6 的保证字典顺序 "unpack" 格式化程序按照其声明的顺序并将它们与 inputs 可变参数分开。

def transform(*inputs, **tranformer):
    return [f(val) for val, f in zip(inputs, tranformer.values())]

size, duration, name = transform(*some_external_function(), f1=int, f2=float, f3=str.lower)

为了使流程更加通用并允许使用预定义的转换函数,您可以使用 operator.partial

from functools import partial

def prep(f_tranformer, *format_funcs):
    formatters = {"f%d"%ix : func for ix, func in enumerate(format_funcs)} 
    return partial(transform, **formatters)


transform2 = prep(transform, int, float, str.lower)

您可以用作:

size, duration, name = transform2(*some_external_function())

我将第二个布鲁诺的回答作为我的首选。我想这将取决于您调用此函数的频率将决定它在重构此类障碍方面的价值。如果你打算多次调用那个外部函数,你也可以考虑装饰它:

from functools import wraps

def type_wrangler(func):
    def wrangler():
        n,s,d = func()
        return str(n), int(s), float(d)
    return wrangler


def external_func():
    return 'a_name', '10', '5.6'

f = type_wrangler(external_func)

print(f())