函数式编程的pythonic风格

函数式编程的pythonic风格,python,functional-programming,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中做一些类似的事情,但我无法获得相同的链接样式。我不得不把它分解成两种

我对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')
我有两个问题:

  • Python中有没有方法接近第一种样式
  • Python中的惯用方法是什么
  • 谢谢。

    生成器表达式是Pythonic方法,但是可以通过和的组合使用功能解决方案:


    在python中,他们使用
    map
    filter
    以函数式的方式(实际上不是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))
    

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

    这条硬性的规则有点笨拙,当然有一些方法可以使用典型的函数工具,如
    map
    filter
    、和
    reduce
    (在Python中称为
    functools.reduce
    ),来完成您想要完成的任务,但很可能您的函数代码看起来比sin更丑陋,在这种情况下,没有理由喜欢它,而不是一些必要的、漂亮的东西

    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]
    

    如果您愿意使用第三方库,我建议您使用
    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')
    

    实际上,javascript看起来功能性不强。好吧,你可以做功能性的,但很可能你的合作者会因此而憎恨你(:如果你也和一个功能性的人一起工作,那就千方百计去做(:@Joey Mallone既不是JavaScript/Java,但OP希望这样写你的嵌套
    for
    -循环示例是任何东西,但不是Pythonic。生成器表达式和理解有什么问题吗?@EliKorvigo这些表达式可以简洁,但这种逻辑所需的嵌套理解很麻烦。实际上我的逻辑是错误的——他想要
    (英雄,电影)如果是“新希望”在电影中
    。我同意@AdamSmith的观点:嵌套列表理解比显式嵌套列表更难理解loops@AdamSmith我想第二条路是我想要的,谢谢you@AdamSmith我个人会在for循环中使用列表comp,即get_heros(“绝地”):results.extend中的英雄的
    ([get_movies(hero)中的电影对电影(如果电影中有“新希望”)
    生成器和生成器表达式(包括列表理解等)实际上是函数式编程的典型-FWIW,列表理解来自Haskell。这是一种真诚的方法,实际上可以是python和函数式的。我认为它会“看”如果您命名正在构建的函数,然后将其单独应用于数据,则效果更好。
    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')