关于python:用于函数式编程的pythonic样式

pythonic style for functional programming

我对Python没有太多经验。我试图用像Java和JavaScript这样的函数式编写代码。

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

我正在尝试用Python做类似的事情,但是我不能得到相同的链接样式。我不得不把它分为两种说法,我不喜欢:

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

我有两个问题:

  • 在python中,有没有方法来处理第一种样式?
  • 在Python中,这样做的惯用方法是什么?
  • 谢谢您。


    作为一个热爱函数式编程的人,不要用Python编写函数式的代码。

    这条硬性和快速性的规则有点笨拙,当然也有一些方法可以使用典型的功能性工具,如mapfilterreduce(在python中称为functools.reduce),来完成你想做的工作,但很可能你的功能性代码看起来比s in更丑,在这种情况下,没有理由比某些工具更喜欢它。事情势在必行。

    1
    2
    3
    4
    5
    6
    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
    result = [(hero, movies) for hero in get_heros("Jedi")
              for movies in [get_movies(hero)] if"A New Hope" in movies]


    Generator表达式是一种pythonic方法,但是通过mapfilter的组合可以得到一个函数解:

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


    如果您愿意使用第三方库,我建议您使用fn.py及其用于构图的语法结构。

    1
    2
    3
    4
    5
    6
    7
    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表达式链是一个可以多次使用的新函数。这更接近于经典意义上的函数式编程:程序是组合:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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')


    在我看来,他们在Python中以一种功能性的方式(实际上不是pythonic),使用mapfilter

    1
    2
    3
    4
    5
    6
    7
    result = filter (
        lambda x: x[1].contains('A New Hope'),
        map(
            lambda x: (hero, get_movies(hero)),
            get_heroes('jedi')
        )
    )

    肾盂道(功能不太好)将使用发生器表达:

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