繁体   English   中英

用于函数式编程的 Pythonic 风格

[英]pythonic style for functional programming

我对 Python 没有太多经验。 我正在尝试以 Java 和 JavaScript 习惯的功能风格进行编码

var result = getHeroes('Jedi')
  .map(hero => { hero: hero, movies: getMovies(hero) })
  .filter(x => x.movies.contains('A New Hope'));

我正在尝试在 Python 中做类似的事情,但我无法获得相同的链接样式。 我不得不把它分解成两个我不喜欢的陈述:

tmp = ((hero, get_movies(hero)) for hero in get_heroes('jedi'))
result = ((hero, movies) for (hero, movies) in tmp if movies.contains('A New Hope')

我有两个问题:

  1. Python 有没有办法接近第一种风格?
  2. 在 Python 中这样做的惯用方式是什么?

谢谢你。

作为喜欢函数式编程的人, 不要在Python中使用函数式编写

这个坚硬而快速的规则有点笨拙,并且有一些方法可以使用典型的功能工具(例如mapfilterreduce )来做你正在尝试做的事情(在Python中称为functools.reduce ),但它很可能是你的功能代码看起来会比罪恶更加丑陋,在这种情况下,没有理由更喜欢它而不是命令式和漂亮的东西。

result = []
for hero in get_heros("Jedi"):
    movies = get_movies(hero)
    for movie in movies:
        if "A New Hope" in movies:
            result.append((hero, movies))

这可以通过列表理解来完成,但可能性较差。

result = [(hero, movies) for hero in get_heros("Jedi")
          for movies in [get_movies(hero)] if "A New Hope" in movies]

生成器表达式 Pythonic方法,但通过mapfilter的组合可以实现功能性解决方案:

mapper = map(lambda x: (x, get_movies(x)), get_heroes('jedi'))
result = filter(lambda x: x[1].contains('A New Hope'), mapper)

IMO他们在python(实际上不是pythonic)的功能样式中使用mapfilter

result = filter (
    lambda x: x[1].contains('A New Hope'),
    map(
        lambda x: (hero, get_movies(hero)),
        get_heroes('jedi')
    )
)

pythonic方式(不是非常实用)将使用生成器表达式:

result = ((hero, get_movies(hero)) for hero in get_heroes("jedi") if "A new hope" in get_movies(hero))

如果您愿意使用第三方库,我建议fn.py使用其语法糖作为成分

from fn import F

result = (
    F(map, lambda hero: dict(hero=hero, movies=getMovies(hero))) >>
    (filter, lambda x: 'A New Hope' in x['movies']) >> 
    list
)(getHeroes('Jedi'))

如果您不想要列表,则可以删除合成中的最后一个元素,尽管有状态迭代器/生成器功能不是很强。 F -objects包装callables并使部分应用和组合更容易。 一系列F -expressions是一种可以多次使用的新功能。 这更接近于传统意义上的函数式编程:程序是组合:

program = (
    F(map, lambda hero: dict(hero=hero, movies=getMovies(hero))) >>
    (filter, lambda x: 'A New Hope' in x['movies']) >> 
    list
)

result = program(getHeroes('Jedi'))
# or even
result = (F(getHeroes) >> program)('Jedi')

我很惊讶没有人使用pytoolzpipe提出以下建议:

from toolz import pipe

result = pipe(
    get_heroes("Jedi"),
    lambda hs: [{"hero": h, "movies": get_movies(h)} for h in hs],
    lambda xs: [x for x in xs if "A New Hope" in x["movies"]],
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM