我喜欢python。然而,有一点让我感到困惑的是,我不知道如何以流畅的方式格式化功能活动,就像javascript中的can一样。
示例(在现场随机创建):你能帮助我以流畅的方式将其转换为python吗?
var even_set = [1,2,3,4,5]
.filter(function(x){return x%2 === 0;})
.map(function(x){
console.log(x); // prints it for fun
return x;
})
.reduce(function(num_set, val) {
num_set[val] = true;
}, {});
我想知道是否有流体选择?也许是一个图书馆。
一般来说,我一直在使用列表推导来处理大多数事情,但如果我想要打印它就是一个真正的问题
例如,如何使用列表理解(Python 3 print()作为函数打印python 2.x中的1到5之间的每个偶数,但是Python 2它不会打印)。构建并返回列表也有点烦人。我宁愿只是为了循环。答案 0 :(得分:2)
尽管反对这样做的争论,这里是对你的JS代码的Python的翻译。
from __future__ import print_function
from functools import reduce
def print_and_return(x):
print(x)
return x
def isodd(x):
return x % 2 == 0
def add_to_dict(d, x):
d[x] = True
return d
even_set = list(reduce(add_to_dict,
map(print_and_return,
filter(isodd, [1, 2, 3, 4, 5])), {}))
它应该适用于Python 2和Python 3。
答案 1 :(得分:2)
理解是处理过滤器/地图操作的流畅的python方式。
您的代码类似于:
def evenize(input_list):
return [x for x in input_list if x % 2 == 0]
理解对于控制台日志记录这样的副作用效果不佳,所以在单独的循环中这样做。链接函数调用并不是python中常见的习惯用法。不要指望这是你的面包和黄油。 Python库倾向于遵循“更改状态或返回值,但不是两者”模式。存在一些例外情况。
编辑:从好的方面来说,python提供了几种理解,非常棒:
列表理解:[x for x in range(3)] == [0, 1, 2]
设置理解:{x for x in range(3)} == {0, 1, 2}
Dict理解:`{x:x ** 2 for x in range(3)} == {0:0,1:1,2:4}
生成器理解(或生成器表达式):(x for x in range(3)) == <generator object <genexpr> at 0x10fc7dfa0>
通过生成器理解,尚未对任何内容进行评估,因此在对大型集合进行流水线操作时,这是一种防止内存使用量上升的好方法。
例如,如果您尝试执行以下操作,即使使用range
的python3语义:
for number in [x**2 for x in range(10000000000000000)]:
print(number)
尝试构建初始列表时会出现内存错误。另一方面,将列表理解更改为生成器理解:
for number in (x**2 for x in range(1e20)):
print(number)
并且没有内存问题(它只需要永远运行)。所发生的是范围对象被构建(其仅存储开始,停止和步骤值(0,1e20和1))对象被构建,然后for循环开始迭代genexp对象。实际上,for循环调用
GENEXP_ITERATOR = `iter(genexp)`
number = next(GENEXP_ITERATOR)
# run the loop one time
number = next(GENEXP_ITERATOR)
# run the loop one time
# etc.
(注意GENEXP_ITERATOR对象在代码级别不可见)
next(GENEXP_ITERATOR)
尝试从genexp中取出第一个值,然后开始在范围对象上迭代,拉出一个值,将其平方,并将该值作为第一个number
输出。下一次for循环调用next(GENEXP_ITERATOR)
时,生成器表达式从范围对象中拉出第二个值,对其进行平方并将其输出为for循环中的第二个传递。第一组数字不再保留在内存中。
这意味着无论生成器理解中有多少项,内存使用量都保持不变。您可以将生成器表达式传递给其他生成器表达式,并创建从不占用大量内存的长管道。
def pipeline(filenames):
basepath = path.path('/usr/share/stories')
fullpaths = (basepath / fn for fn in filenames)
realfiles = (fn for fn in fullpaths if os.path.exists(fn))
openfiles = (open(fn) for fn in realfiles)
def read_and_close(file):
output = file.read(100)
file.close()
return output
prefixes = (read_and_close(file) for file in openfiles)
noncliches = (prefix for prefix in prefixes if not prefix.startswith('It was a dark and stormy night')
return {prefix[:32]: prefix for prefix in prefixes}
在任何时候,如果你需要一个数据结构,你可以将生成器理解传递给另一个理解类型(如本例的最后一行),此时,它将强制生成器评估所有他们留下的数据,但除非你这样做,否则内存消耗将限于通过发生器的单次传递。
答案 2 :(得分:2)
生成器,迭代器和CREATE FUNCTION [hash].[HashDelimiter2]()
RETURNS NCHAR(1)
WITH SCHEMABINDING
AS BEGIN
RETURN N';'
END
GO
/* This does indeed result in YES */
SELECT IS_DETERMINISTIC
FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_NAME = 'HashDelimiter2'
/* But then compile it native and it's no longer deterministic */
CREATE FUNCTION [hash].[HashDelimiter3]()
RETURNS NCHAR(1)
WITH NATIVE_COMPILATION, SCHEMABINDING
AS BEGIN ATOMIC WITH (
TRANSACTION ISOLATION LEVEL = SNAPSHOT,
LANGUAGE = N'English'
)
RETURN N';'
END
GO
/* This results in NO */
SELECT IS_DETERMINISTIC
FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_NAME = 'HashDelimiter3'
为链接和过滤操作提供了额外的功能。但是,我不是记住(或查找)很少使用的东西,而是倾向于帮助函数和理解。
例如,在这种情况下,请使用辅助函数来处理日志记录:
itertools
使用理解的def echo(x):
print(x)
return x
子句可以轻松选择偶数值。由于最终输出是字典,请使用这种理解:
if
或要将这些值添加到现有字典中,请使用In [118]: d={echo(x):True for x in s if x%2==0}
2
4
In [119]: d
Out[119]: {2: True, 4: True}
。
update
另一种写这个的方法是使用中间生成器:
new_set.update({echo(x):True for x in s if x%2==0})
或者将回声和滤波器组合在一个发生器中
{y:True for y in (echo(x) for x in s if x%2==0)}
然后使用它进行dict comp:
def even(s):
for x in s:
if x%2==0:
print(x)
yield(x)
答案 3 :(得分:1)
您编写的代码最大的破坏者是Python不支持多行匿名函数。 filter
或map
的返回值是一个列表,因此如果您愿意,可以继续链接它们。但是,您必须提前定义函数,或使用lambda。
答案 4 :(得分:1)
我现在正在寻找一个更贴近问题核心的答案:
fluentpy
https://pypi.org/project/fluentpy/:
以下是streams
程序员(在scala
,java
等中)所喜欢的集合的方法链接:
import fluentpy as _
(
_(range(1,50+1))
.map(_.each * 4)
.filter(_.each <= 170)
.filter(lambda each: len(str(each))==2)
.filter(lambda each: each % 20 == 0)
.enumerate()
.map(lambda each: 'Result[%d]=%s' %(each[0],each[1]))
.join(',')
.print()
)
我现在正在尝试这个。如果上面显示的那样,今天将是非常愉快的一天。
更新:看一下:也许python
可以开始变得更合理,因为它是单行shell脚本:
python3 -m fluentpy "lib.sys.stdin.readlines().map(str.lower).map(print)"
这是在命令行上执行的操作:
$echo -e "Hello World line1\nLine 2\Line 3\nGoodbye"
| python3 -m fluentpy "lib.sys.stdin.readlines().map(str.lower).map(print)"
hello world line1
line 2
line 3
goodbye
还有一个额外的newline
应该被清理-但要点是有用的(无论如何对我来说)。
答案 5 :(得分:1)
已经有一个库可以完全满足您的需求,即流畅的语法,惰性求值和操作顺序与编写方式相同,还有其他许多好东西,例如多进程或多线程Map /降低。
它的名称为pyxtension
,并且已经准备好并在PyPi上进行维护。
您的代码将以以下形式重写:
from pyxtension.strams import stream
def console_log(x):
print(x)
return x
even_set = stream([1,2,3,4,5])\
.filter(lambda x:x%2 === 0)\
.map(console_log)\
.reduce(lambda num_set, val: num_set.__setitem__(val,True))
对于多进程映射,将map
替换为mpmap
,对于多线程映射,将fastmap
替换。