Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中干净的操作管道_Python_Functional Programming_Pipeline - Fatal编程技术网

python中干净的操作管道

python中干净的操作管道,python,functional-programming,pipeline,Python,Functional Programming,Pipeline,我有一个很长的管道,它对字符串列表执行各种操作input\u list。管道将每个单词映射为小写,替换下划线,过滤掉特定单词,删除重复项,并将片段剪辑到特定长度 result = list(set(filter(lambda x : x != word, map(lambda x : x.lower().replace('_',' '), input_list))))[:clip_length] 我的问题是它的可读性不是很强:它不太清楚这个管道的输入是什么,操作的应用顺序是什么。看一眼会很痛,

我有一个很长的管道,它对字符串列表执行各种操作
input\u 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]

这就是功能性风格,你们可以从最里面的表达到最外面的表达

在多行中添加一些注释有助于提高可读性:

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]

嗯,它很实用,但没有(一致的)风格。“问题”是用于这些表达式的语法种类繁多

  • 调用func时使用普通前缀表示法
    f(arg)
  • 获取子数组使用特殊语法
    arr[n?:m?]
    ,而不是函数
    slice(n,m)
  • set
    是一种完全不同的类型,但它被中间使用,因为集合恰好具有我们想要的一些行为-我们想要的是iterable中的“惟一”元素,因此我们的函数应该被称为
    unique
    。如果我们碰巧使用
    集合
    来实现
    独特的
    ,那没关系,但这不是读者所关心的问题,因为读者的思维不会受到这些干扰
  • x.lower()
    是一个动态调用,
    lower
    处于中缀位置。比较前缀位置
    下(x)
    。这同样适用于
    s.replace(pat,rep)
    vs
    replace(s,pat,rep)
  • map
    filter
    但是它们有一个功能接口
    map(f,iter)
    filter(f,iter)
但是,要编写一个类似于您共享的程序,有点遗漏了函数式最强大、最通用的特性:函数。是的,函数式编程也是关于组成漂亮的表达式链,但不是以可读性为代价!如果可读性开始受损,请使用。。。a函数: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 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']
现在是依赖关系。每个函数仅对其参数进行操作,并返回一个输出

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
在如何使用现有的语言特性解决uniques问题方面显示了良好的直觉,但我们希望恢复引用的透明度。在上面的程序中,通过调用
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 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 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']

上触摸并试验此程序。它很实用,但没有(一致的)风格。“问题”是用于这些表达式的语法种类繁多

  • 调用func时使用普通前缀表示法
    f(arg)
  • 获取子数组使用特殊语法
    arr[n?:m?]
    ,而不是函数
    slice(n,m)
  • set
    是一种完全不同的类型,但它被中间使用,因为集合恰好具有我们想要的一些行为-我们想要的是iterable中的“惟一”元素,因此我们的函数应该被称为
    unique
    。如果我们碰巧使用
    集合
    来实现
    独特的
    ,那没关系,但这不是读者所关心的问题,因为读者的思维不会受到这些干扰
  • x.lower()
    是一个动态调用,
    lower
    处于中缀位置。比较前缀位置
    下(x)
    。这同样适用于
    s.replace(pat,rep)
    vs
    replace(s,pat,rep)
  • map
    filter
    但是它们有一个功能接口
    map(f,iter)
    filter(f,iter)
但是写一个程序