python 中缀前向管道

python infix forward pipe

我正在尝试实现转发管道功能,例如 bash 的 | 或 R 最近的 %>%。我见过这个实现 https://mdk.fr/blog/pipe-infix-syntax-for-python.html,但这需要我们预先定义所有可能与管道一起使用的函数。在寻求完全通用的东西时,这是我到目前为止的想法。

这个函数将它的第一个参数应用到它的第二个(一个函数)

def function_application(a,b):
    return b(a)

例如,如果我们有一个平方函数

def sq(s):
    return s**2

我们可以用这种麻烦的方式调用该函数 function_application(5,sq)。为了更接近前向管道,我们想使用 function_application 和中缀符号。

借鉴this,我们可以定义一个Infix class,这样我们就可以用|等特殊字符包装函数。

class Infix:
    def __init__(self, function):
        self.function = function
    def __ror__(self, other):
        return Infix(lambda x, self=self, other=other: self.function(other, x))
    def __or__(self, other):
        return self.function(other)

现在我们可以定义我们的管道,它只是函数的中缀版本 function_application

p = Infix(function_application)

所以我们可以这样做

5 |p| sq
25

[1,2,3,8] |p| sum |p| sq
196

在冗长的解释之后,我的问题是是否有任何方法可以超越 valid function names 的限制。在这里,我将管道命名为 p,但是是否可以重载非字母数字字符?我可以命名一个函数 > 所以我的管道是 |>| 吗?

快速回答:

你不能真正在 python 中使用 |>|,你至少需要 | * > * |,其中 * 需要是标识符、数字、字符串,或其他表达式。

长答案:

每一行都是一条语句(simple or compound), a stmt can be a couple of things, among them an expression, an expression is the only construct that allows the use of or operator | and greater than comparison > (or all operators and comparisons for that matter < > <= >= | ^ & >> << - + % / //), every expression needs a left hand side and a right hand side, ultimatelly being in the form lhs op rhs, both left and right hand side could be another expression, but the exit case is the use of an primary (with the exception of unnary -, ~ and + that need just a rhs), the primary will boil down to an identifier, number or string, so, at the end of the day you are required to have an identifier [a-zA-Z_][a-zA-Z_0-9]* 旁边是 |.

您是否考虑过一种不同的方法,例如 class 覆盖 or 运算符而不是中缀 class?我有一个做管道的 tiny library,你可能会感兴趣

作为参考,这里是完整的语法:

https://docs.python.org/2/reference/grammar.html

我也在寻找一种方法来做到这一点。所以我创建了一个名为 Pypework.

的 Python 库

您只需在每个函数调用的开头添加一个前缀,例如 f.,使其可通过管道传输。然后您可以使用 >> 运算符将它们链接在一起,如下所示:

"Lorem Ipsum" >> f.lowercase >> f.replace(" ", "_") # -> "lorem_ipsum"

或者如果括在括号中则跨多行,如下所示:

(
  "Lorem Ipsum"
    >> f.lowercase
    >> f.replace(" ", "_")
)

# -> "lorem_ipsum"