函数式编程的pythonic风格

时间:2019-01-04 09:43:39

标签: python 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中惯用的方式是什么?

谢谢。

4 个答案:

答案 0 :(得分:4)

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

这条硬朗的规则有些牵强,并且肯定有多种方法可以使用mapfilter和{{1 }}(在Python中称为reduce),但您的功能代码看起来可能比罪恶的丑陋,在这种情况下,没有必要比命令式的和漂亮的东西更喜欢它。

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))

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

IMO,他们使用mapfilter在python中(实际上不是pythonic)以一种功能样式实现此目的:

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))

答案 3 :(得分:1)

如果您愿意使用第三方库,我建议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-对象包装可调用对象,并使部分应用程序和编写更加容易。 F表达式链是一个可以多次使用的新函数。从经典意义上来说,这更接近于函数式编程:程序就是组合:

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')