问题描述
在R中(感谢 dplyr
),您现在可以通过%>%$ c $执行更多功能的管道语法C>。这意味着,而不是编码:
> as.Date(2014-01-01)
> as.character((sqrt(12)^ 2)
您也可以这样做:
>2014-01-01%>%as.Date
> 12%>%sqrt% >%。^ 2%>%as.character
对我来说这更具可读性,扩展到数据框以外的用例python语言是否支持类似的东西?
解决方案通过使用称为的模块,Macropy允许您将转换应用于(code> a | b
)可以转换为 b(a)
。优点和缺点。 与Sylvain Leroux提到的解决方案相比,主要优点是您不需要为您感兴趣的功能创建中缀对象 - 只需标记您打算使用的代码区域即可他转变。其次,由于转换是在编译时而不是运行时应用的,因此转换后的代码在运行时不会受到任何开销 - 所有工作都是在字节代码首次从源代码生成时完成的。
主要缺点是macropy需要一定的方式才能激活它(稍后会提到)。与更快的运行时相反,源代码的解析在计算上更复杂,因此程序启动需要更长的时间。最后,它增加了一种语法风格,意味着不熟悉macropy的程序员可能会发现你的代码难以理解。
示例代码:
run.py
import macropy.activate
#激活macropy,使用macropy的模块不能在程序中的这个语句
#之前导入。
导入目标
#使用macropy
导入模块
目标。 py
from fpipe导入宏,fpipe
from macropy.quick_lambda导入宏,f
#从模块导入宏,...必须用于macropy,以知道应该将哪些
#宏应用于您的代码。
#这里有两个宏被导入了`fpipe`,它可以做
#和`f`,它提供了一种更快的方式来编写lambdas。
从数学导入sqrt
#在单个表达式中使用fpipe宏。
#方括号之间的代码被解释为 - str(sqrt(12))
print fpipe [12 | sqrt | str]#打印3.46410161514
#使用装饰器
#检查函数中的所有代码是否为`x | y`构造。
x = 1#全局变量
@fpipe
def sum_range_then_square():
期望值(1 + 2 + 3)** 2 - > 36
y = 4#局部变量
返回范围(x,y)|总和| f [_ ** 2]
#`f [_ ** 2]`是macropy的语法: - lambda x:x ** 2`,这也可以在这里工作
打印sum_range_then_square()#使用带块的方式打印36
#。
#与装饰器相同,但是用于限制块。
与fpipe:
打印范围(4)|总和#打印6
打印'a b c'| f [_。split()]#prints ['a','b','c']
fpipe.py
from macropy.core.macros import *
from macropy.core.quotes import macros,q,ast
宏=宏()
@ macros.decorator
@ macros.block
@ macros.expr
def fpipe(tree,** kw) :
@Walker
def pipe_search(tree,stop,** kw):
按位或运算符搜索代码并将`a | b`转换为`b (a)`。
如果isinstance(tree,BinOp)和isinstance(tree.op,BitOr):
operand = tree.left
function = tree.right
newtree = q [ast [function](ast [operand])]
return newtree
return pipe_search.recurse(tree)
In R (thanks to dplyr
) you can now perform operations with a more functional piping syntax via %>%
. This means that instead of coding this:
> as.Date("2014-01-01")
> as.character((sqrt(12)^2)
You could also do this:
> "2014-01-01" %>% as.Date
> 12 %>% sqrt %>% .^2 %>% as.character
To me this is more readable and this extends to use cases beyond the dataframe. Does the python language have support for something similar?
One possible way of doing this is by using a module called macropy
. Macropy allows you to apply transformations to the code that you have written. Thus a | b
can be transformed to b(a)
. This has a number of advantages and disadvantages.
In comparison to the solution mentioned by Sylvain Leroux, The main advantage is that you do not need to create infix objects for the functions you are interested in using -- just mark the areas of code that you intend to use the transformation. Secondly, since the transformation is applied at compile time, rather than runtime, the transformed code suffers no overhead during runtime -- all the work is done when the byte code is first produced from the source code.
The main disadvantages are that macropy requires a certain way to be activated for it to work (mentioned later). In contrast to a faster runtime, the parsing of the source code is more computationally complex and so the program will take longer to start. Finally, it adds a syntactic style that means programmers who are not familiar with macropy may find your code harder to understand.
Example Code:
run.py
import macropy.activate
# Activates macropy, modules using macropy cannot be imported before this statement
# in the program.
import target
# import the module using macropy
target.py
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']
And finally the module that does the hard work. I've called it fpipe for functional pipe as its emulating shell syntax for passing output from one process to another.
fpipe.py
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)
这篇关于Python中的功能管道,比如R的dplyr中的%>%的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!