繁体   English   中英

清理python中的操作管道

[英]Clean pipeline of operations in python

我有一条很长的管道,可以对输入字符串input_list各种操作。 管道将每个单词映射为小写字母,替换下划线,过滤出特定单词,删除重复项,并将片段剪辑为特定长度。

result = list(set(filter(lambda x : x != word, map(lambda x : x.lower().replace('_',' '), input_list))))[:clip_length]

我的问题是它的可读性很差:它不清楚该管道的输入是什么以及以什么顺序应用操作。 稍微看一下会很痛,除非它被很好地评论,否则以后我可能不知道它会做什么。

有什么方法可以在python中编写管道,在其中我可以清楚地看到哪些操作以什么顺序发生,什么进来什么,什么出去? 更具体地说,我希望能够编写它,以便操作从右到左或从左到右,而不是从内到外。

这是一种功能样式,您可以从最里面的表达式到最外面的表达式进行阅读。

将其放在多行中并添加一些注释可以提高可读性:

result = list(                                # (5) convert to list
  set(                                        # (4) convert to set (remove dupes)
    filter(
      lambda x: x != word,                    # (3) filter items != to word
      map(
        lambda x: x.lower().replace('_',' '), # (2) apply transformation
        input_list                            # (1) take input_list
      )
    )
  )
)[:clip_length]                               # (6) limit number of results

这是一个品味问题。 我倾向于使用像这样的单个表达式,并采用最小的格式使其能够很好地适合:

result = list(set(filter(lambda x : x != word,
    map(lambda x : x.lower().replace('_',' '), input_list))))[:clip_length]

等效的命令式处理是:

result = set()
for x in input_list:
    x = x.lower().replace('_', ' ')
    if x != word:
        result.add(x)
result = list(result)[:clip_length]

它功能齐全,但是没有(一致)样式。 “问题”是用于这些表达式的多种语法。

  • 调用函数是通过普通前缀符号f(arg)
  • 获取子数组使用特殊语法arr[n?:m?] ,而不是函数slice(n,m)
  • set是一种完全不同的类型,但是在中间使用它是因为set恰好具有我们想要的某些行为-我们想要的是可迭代的“唯一”元素,因此我们的函数应称为unique 如果我们碰巧使用set来实现unique ,那很好,但这不是读者的关注点,他们的思想不受这种干扰
  • x.lower()是动态调用, lower infix位置lower 比较前缀位置lower(x) s.replace(pat,rep) vs replace(s, pat, rep)同样适用
  • mapfilter但是具有功能接口map(f,iter)filter(f,iter)

但是,要编写一个与您共享的程序一样的程序,可能会错过功能样式最强大,用途最广泛的特征:功能。 是的,函数式编程还涉及组成漂亮的表达式链,但并不以可读性为代价! 如果可读性开始受到损害,请使用...功能使其更好。:D

考虑使用统一功能样式的该程序。 它仍然是常规的python程序。

def program (word = '', clip_length = 5, input = ''):
  make_words = \
    compose ( lower
            , partial (replace, '_', ' ')
            )

  process = \
    compose ( partial (map, make_words)
            , partial (filter, lambda x: x != word)
            , unique
            , partial (take, clip_length)
            )

  return process (input)

print (program ('b', 4, 'A_a_a_B_b_b_c_c_c_d_e'))
# ['d', ' ', 'e', 'a']
# Note, your output may vary. More on this later.

现在是依赖项。 每个函数仅对其参数进行操作,并返回输出。

def partial (f, *xs):
  return lambda *ys: f (*xs, *ys)

def compose (f = None, *fs):
  def comp (x):
    if f is None:
      return x
    else:
      return compose (*fs) (f (x))
  return comp

def take (n = 0, xs = []):
  return xs [:n]

def lower (s = ''):
  return s .lower ()

def replace (pat = '', rep = '', s = ''):
  return s .replace (pat, rep)

def unique (iter):
  return list (set (iter))

的确,对于这些要点中的某些问题,这个问题无法设置一个更好的阶段。 我将重新讨论原始问题(以及上面的程序)中使用的set的选择,因为存在一个巨大的问题:如果您多次运行我们的程序,我们将获得不同的输出。 用幻想的话来说,我们没有参照透明性 这是因为Python的集合是无序的,并且当我们从有序列表转换成集合然后再返回到列表时,不能保证我们总是得到相同的元素。

通过这种方式使用set可以很好地了解如何使用现有语言功能解决唯一性问题,但是我们希望恢复参照透明性。 在上面的程序中,我们明确地编码了通过调用输入上的unique函数来获得输入唯一元素的意图。

# deterministic implementation of unique
def unique (iter):
  result = list ()
  seen = set ()
  for x in iter:
    if x not in seen:
      seen .add (x)
      result .append (x)
  return result

现在,当我们运行程序时,我们总是得到相同的结果

print (program ('b', 4, 'A_a_a_B_b_b_c_c_c_d_e'))
# ['a', ' ', 'c', 'd']
# always the same output now

这把我引到了另一点。 因为我们将unique抽象为它自己的函数,所以我们会自动获得一个范围来定义其行为。我选择在unique的实现中使用命令式样式,但这很好,因为它仍然是纯函数并且是函数的使用者无法区别。 只要program可以工作,您就可以提出其他100种unique实现方式,这无关紧要。

函数式编程与函数有关。 该语言是您的驯服语言。 它仍然是常规的python程序。

def fwd (x):
  return lambda k: fwd (k (x))

def program (word = '', clip_length = 5, input = ''):
  make_words = \
    compose ( lower
            , partial (replace, '_', ' ')
            )

  fwd (input)                               \
    (partial (map, make_words))             \
    (partial (filter, lambda x: x != word)) \
    (unique)                                \
    (partial (take, clip_length))           \
    (print)

program ('b', 4, 'A_a_a_B_b_b_c_c_c_d_e')
# ['a', ' ', 'c', 'd']

repl.it上触摸并试验该程序

暂无
暂无

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

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