如何组合两个函数,其外部函数为内部函数提供参数

Tom*_*Tom 12 python functional-programming

我有两个类似的代码需要解析,我不确定实现这个的最pythonic方式.

假设我有两个相似的"代码"

secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing'
secret_code_2 = 'qwersdfg-qw|er$$otherthing'
Run Code Online (Sandbox Code Playgroud)

两个代码以...结尾$$otherthing并包含多个值-

起初我想过functools.wrap将一些常用逻辑与特定于每种类型代码的逻辑分开,如下所示:

from functools import wraps

def parse_secret(f):
  @wraps(f)
  def wrapper(code, *args):
    _code = code.split('$$')[0]
    return f(code, *_code.split('-'))
  return wrapper

@parse_secret
def parse_code_1b(code, a, b, c):
  a = a.split('|')[0]
  return (a,b,c)

@parse_secret
def parse_code_2b(code, a, b):
  b = b.split('|')[1]
  return (a,b)
Run Code Online (Sandbox Code Playgroud)

但是这样做会让你有点混淆你应该实际传递给parse_code_*函数的参数,即

parse_code_1b(secret_code_1)
parse_code_2b(secret_code_2)
Run Code Online (Sandbox Code Playgroud)

因此,为了更容易理解函数的形式参数,我将逻辑更改为:

def _parse_secret(parse_func, code):
  _code = code.split('$$')[0]
  return parse_func(code, *_code.split('-'))

def _parse_code_1(code, a, b, c):
  """
  a, b, and c are descriptive parameters that explain
  the different components in the secret code

  returns a tuple of the decoded parts
  """
  a = a.split('|')[0]
  return (a,b,c)

def _parse_code_2(code, a, b):
  """
  a and b are descriptive parameters that explain
  the different components in the secret code

  returns a tuple of the decoded parts
  """
  b = b.split('|')[1]
  return (a,b)

def parse_code_1(code):
  return _parse_secret(_parse_code_1, code)

def parse_code_2(code):
  return _parse_secret(_parse_code_2, code)
Run Code Online (Sandbox Code Playgroud)

现在,更容易推断你传递给函数的内容:

parse_code_1(secret_code_1)
parse_code_2(secret_code_2)
Run Code Online (Sandbox Code Playgroud)

但是这段代码更加冗长.

有一个更好的方法吗?面向对象的方法在这里会更有意义吗?

repl.it例子

Dar*_*ght 2

复制示例

函数式方法更加简洁并且更有意义。

我们可以从用纯函数表达概念开始,这是最容易组合的形式。

剥离$$otherthing和分割值:

parse_secret = lambda code: code.split('$$')[0].split('-')
Run Code Online (Sandbox Code Playgroud)

取内部值之一:

take = lambda value, index: value.split('|')[index]
Run Code Online (Sandbox Code Playgroud)

将其中一个值替换为其内部值:

parse_code = lambda values, p, q: \
  [take(v, q) if p == i else v for (i, v) in enumerate(values)]
Run Code Online (Sandbox Code Playgroud)

这两种类型的代码有 3 个区别:

  • 值的数量
  • 解析“内部”值的位置
  • “内在”价值观的定位

我们可以通过描述这些差异来编写解析函数。分割值保持打包状态,以便更容易组合。

compose = lambda length, p, q: \
  lambda code: parse_code(parse_secret(code)[:length], p, q)

parse_code_1 = compose(3, 0, 0)
parse_code_2 = compose(2, 1, 1)
Run Code Online (Sandbox Code Playgroud)

并使用组合函数:

secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing'
secret_code_2 = 'qwersdfg-qw|er$$otherthing'
results = [parse_code_1(secret_code_1), parse_code_2(secret_code_2)]
print(results)
Run Code Online (Sandbox Code Playgroud)

  • 使用命名 lambda 函数是 [PEP8 不鼓励](http://www.python.org/dev/peps/pep-0008/#programming-recommendations) (2认同)