用于非平凡列表推导的惯用Python

hbr*_*tow 6 python idiomatic

在Python中对iterable执行简单转换是通过列表解析来实现的:

y = [f(arg) for arg in args]
Run Code Online (Sandbox Code Playgroud)

where f是一个简单的语句,或者一个函数mapif f是一个命名函数:

y = map(f, args)
Run Code Online (Sandbox Code Playgroud)

圭多有利于列表解析map(lambda x:..., args),确实列表内涵上的使用mapfilter 在所有.

但是,我不清楚我应该如何解决以下问题:

  • 修改可迭代的每个元素,
  • 以非平凡的方式,
  • 使用一个独立的逻辑(可能是一个函数),
  • 这在其他任何地方都没用

解决此类问题最常用的方法是什么?我见过并尝试过的一些我已经参与过的Python项目:

Predeclare和循环

显而易见的方法是预先声明输出和循环:

def transform(...):

    ...

    y = []
    for arg in args:
        first_statement
        second_statement
        ...
        y.append(statement)
Run Code Online (Sandbox Code Playgroud)

评论:

  • (亲)容易遵循逻辑
  • (con)逻辑没有作用域(泄漏抽象)
  • (con)逻辑不明确(你怎么知道它是一个地图而不检查循环中所有分支是如何运作的?)
  • (con)以一种无用的方式不必要地预先声明变量(y必须与长度相同args)

嵌套函数

另一种选择是将逻辑封装在嵌套函数中,然后使用map或list comprehension调用它:

def transform(...):

    ...

    def anonymous(arg):
        first_statement
        second_statement
        ...
        return statement

    y = map(anonymous, args)
    # y = [anonymous(arg) for arg in args]
Run Code Online (Sandbox Code Playgroud)

评论:

  • (专业版)封装逻辑
  • (专业版)可以访问外部范围
  • (专业)不能修改外部范围(明确没有副作用)
  • (Con)每次调用内部函数时都会重新定义
  • (Con)内部函数没有实名(在地图范围内应该是匿名的)

外部功能

将内部函数移动到外部范围解决了其中一些问题,但介绍了更多:

def _anonymous(arg):
    first_statement
    second_statement
    ...
    return statement

def transform(...):

    ...

    y = map(_anonymous, args)
Run Code Online (Sandbox Code Playgroud)

评论:

  • (专业):函数在分析时编译一次
  • (Con):对于一小段逻辑,函数离调用站点太远(导致程序员不必要的上下文切换)
  • (Con):函数无法访问外部作用域.任何要求必须传递(防止使用map)或partialized

摘要

我很矛盾.你如何解决你需要做一个非平凡的丢弃地图的问题?