一种可行的方法是使用名为的模块macropy
。Macropy允许您将转换应用于所编写的代码。因此a | b
可以转换为b(a)
。这具有许多优点和缺点。
与Sylvain Leroux提到的解决方案相比,主要优点是您不需要为要使用的功能创建中缀对象- 只需标记要使用转换的代码区域即可。其次,由于转换是在编译时而不是在运行时应用的,因此转换后的代码在运行时不会受到开销- 所有工作都是在最初从源代码生成字节代码时完成的。
主要缺点是,宏需要某种特定的激活方式才能起作用(稍后会提到)。与更快的运行时间相比,源代码的解析在计算上更加复杂,因此程序将需要更长的启动时间。最后,它添加了一种语法样式,这意味着不熟悉宏的程序员可能会发现您的代码更难理解。
import macropy.activate
# Activates macropy, modules using macropy cannot be imported before this statement
# in the program.
import target
# import the module using macropy
from fpipe import macros, fpipe
from macropy.quick_lambda import macros, f
# The `from module import macros, ...` must be used for macropy to kNow which
# macros it should apply to your code.
# Here two macros have been imported `fpipe`, which does what you want
# and `f` which provides a quicker way to write lambdas.
from math import sqrt
# Using the fpipe macro in a single expression.
# The code between the square braces is interpreted as - str(sqrt(12))
print fpipe[12 | sqrt | str] # prints 3.46410161514
# using a decorator
# All code within the function is examined for `x | y` constructs.
x = 1 # global variable
@fpipe
def sum_range_then_square():
"expected value (1 + 2 + 3)**2 -> 36"
y = 4 # local variable
return range(x, y) | sum | f[_**2]
# `f[_**2]` is macropy Syntax for -- `lambda x: x**2`, which would also work here
print sum_range_then_square() # prints 36
# using a with block.
# same as a decorator, but for limited blocks.
with fpipe:
print range(4) | sum # prints 6
print 'a b c' | f[_.split()] # prints ['a', 'b', 'c']
最后是完成工作的模块。我称它为功能管道的fpipe,是它的模拟shell语法,用于将输出从一个进程传递到另一个进程。
from macropy.core.macros import *
from macropy.core.quotes import macros, q, ast
macros = Macros()
@macros.decorator
@macros.block
@macros.expr
def fpipe(tree, **kw):
@Walker
def pipe_search(tree, stop, **kw):
"""Search code for bitwise or operators and transform `a | b` to `b(a)`."""
if isinstance(tree, BinOp) and isinstance(tree.op, BitOr):
operand = tree.left
function = tree.right
newtree = q[ast[function](ast[operand])]
return newtree
return pipe_search.recurse(tree)