如何映射或嵌套Python 2.7 函数发生器?
How to map or nest Python 2.7 function generators?
如果我在 Python 2.7 中有一个非常简单(尽管可能非常复杂)的函数生成器,就像这样:
def accumulator():
x = yield 0
while True:
x += yield x
哪个可以用,像这样:
>>> a = accumulator()
>>> a.send(None)
0
>>> a.send(1)
1
>>> a.send(2)
3
>>> a.send(3)
6
除了乘以 2 之外,另一个产生相同结果的函数生成器的简单包装器是什么?上面的函数生成器很简单,但请假设它太复杂而无法复制粘贴。我正在尝试一些东西,例如:
def doubler():
a = accumulator()
a.send(None)
y = yield 0
while True:
y = 2 * a.send(yield y)
或者,想象一些更简单的事情:
def doubler():
a = accumulator()
a.send = lambda v: 2 * super(self).send(v)
return a
两者都非常糟糕,所以我不会分享语法错误,但它可以说明我正在尝试做的事情。
理想情况下,我想得到一些东西,比如:
>>> d = doubler()
>>> d.send(None)
0
>>> d.send(1)
2
>>> d.send(2)
6
>>> d.send(3)
12
结果与原始结果完全相同,只是加倍了。
我试图避免复制一个非常复杂的函数生成器来创建相同的结果,除了按已知因子缩放。
第二个生成器最终将有一个不同的输入流,所以我不能只使用第一个生成器的结果并将其加倍。我需要第二个独立的发电机,包装第一个。
输入流是不确定的,因此不可能生成整个序列然后进行转换。
我似乎想映射或嵌套这些函数生成器,但我不确定合适的行话,所以我在 Google.
中毫无进展
我没试过这个,但大致是这样的:
class Doubler:
def __init__(self, g):
self.g = g()
def __next__(self):
return self.send(None)
def send(self, val):
return self.g.send(val)*2
此外,在 Python 3.5 之后,从 collections.abc.Container
扩展这个将消除 __next__
的需要,也将使它成为一个合适的生成器(它目前不支持 __throw__
等,但它们只是样板文件)。
编辑:是的,这有效:
In [1]: %paste
def accumulator():
x = yield 0
while True:
x += yield x
## -- End pasted text --
In [2]: %paste
class Doubler:
def __init__(self, g):
self.g = g()
def __next__(self):
return self.send(None)
def send(self, val):
return self.g.send(val)*2
## -- End pasted text --
In [3]: d = Doubler(accumulator)
In [4]: d.send(None)
Out[4]: 0
In [5]: d.send(1)
Out[5]: 2
In [6]: d.send(2)
Out[6]: 6
In [7]: d.send(3)
Out[7]: 12
您只需要将 yield
移动到传递 y
的表达式之外到 a
:
def doubler():
a = accumulator()
next(a)
y = yield 0
while True:
y = yield (2 * a.send(y))
然后:
>>> a = accumulator()
... d = doubler()
... next(a)
... next(d)
... for i in range(10):
... print(a.send(i), d.send(i))
0 0
1 2
3 6
6 12
10 20
15 30
21 42
28 56
36 72
45 90
我想这就是你想要的:
def doubler():
a = accumulator()
y = a.send(None)
x = yield 0
while True:
y = a.send(x)
x = yield 2 * y
这完全包装了 accumulator
实现,但您也可以使其可见并将其作为参数 a
传递给 doubler。
如果您需要与协程具有相同的接口(即具有 send
方法),那么 BrenBarn 的解决方案可能就这么简单。*
如果你可以有一个稍微不同的接口,那么高阶函数就更简单了:
def factor_wrapper(coroutine, factor):
next(coroutine)
return lambda x, c=coroutine, f=factor: f * c.send(x)
您将按如下方式使用它:
>>> a = accumulator()
>>> a2 = factor_wrapper(a, 2)
>>> print a2(1)
2
>>> print a2(2)
6
>>> print a2(3)
12
*实际上你 可以 削减几行使其总共 4 行,虽然并没有真正降低复杂性。
def doubler(a):
y = yield next(a)
while True:
y = yield (2 * a.send(y))
甚至更短...
def doubler(a, y=None):
while True:
y = yield 2 * a.send(y)
以上任意一种都可以按如下方式使用:
>>> a = accumulator()
>>> a2 = doubler(a)
>>> print a2.send(None) # Alternatively next(a2)
0
>>> print a2.send(1)
2
>>> print a2.send(2)
6
>>> print a2.send(3)
12
如果我在 Python 2.7 中有一个非常简单(尽管可能非常复杂)的函数生成器,就像这样:
def accumulator():
x = yield 0
while True:
x += yield x
哪个可以用,像这样:
>>> a = accumulator()
>>> a.send(None)
0
>>> a.send(1)
1
>>> a.send(2)
3
>>> a.send(3)
6
除了乘以 2 之外,另一个产生相同结果的函数生成器的简单包装器是什么?上面的函数生成器很简单,但请假设它太复杂而无法复制粘贴。我正在尝试一些东西,例如:
def doubler():
a = accumulator()
a.send(None)
y = yield 0
while True:
y = 2 * a.send(yield y)
或者,想象一些更简单的事情:
def doubler():
a = accumulator()
a.send = lambda v: 2 * super(self).send(v)
return a
两者都非常糟糕,所以我不会分享语法错误,但它可以说明我正在尝试做的事情。
理想情况下,我想得到一些东西,比如:
>>> d = doubler()
>>> d.send(None)
0
>>> d.send(1)
2
>>> d.send(2)
6
>>> d.send(3)
12
结果与原始结果完全相同,只是加倍了。
我试图避免复制一个非常复杂的函数生成器来创建相同的结果,除了按已知因子缩放。
第二个生成器最终将有一个不同的输入流,所以我不能只使用第一个生成器的结果并将其加倍。我需要第二个独立的发电机,包装第一个。
输入流是不确定的,因此不可能生成整个序列然后进行转换。
我似乎想映射或嵌套这些函数生成器,但我不确定合适的行话,所以我在 Google.
中毫无进展我没试过这个,但大致是这样的:
class Doubler:
def __init__(self, g):
self.g = g()
def __next__(self):
return self.send(None)
def send(self, val):
return self.g.send(val)*2
此外,在 Python 3.5 之后,从 collections.abc.Container
扩展这个将消除 __next__
的需要,也将使它成为一个合适的生成器(它目前不支持 __throw__
等,但它们只是样板文件)。
编辑:是的,这有效:
In [1]: %paste
def accumulator():
x = yield 0
while True:
x += yield x
## -- End pasted text --
In [2]: %paste
class Doubler:
def __init__(self, g):
self.g = g()
def __next__(self):
return self.send(None)
def send(self, val):
return self.g.send(val)*2
## -- End pasted text --
In [3]: d = Doubler(accumulator)
In [4]: d.send(None)
Out[4]: 0
In [5]: d.send(1)
Out[5]: 2
In [6]: d.send(2)
Out[6]: 6
In [7]: d.send(3)
Out[7]: 12
您只需要将 yield
移动到传递 y
的表达式之外到 a
:
def doubler():
a = accumulator()
next(a)
y = yield 0
while True:
y = yield (2 * a.send(y))
然后:
>>> a = accumulator()
... d = doubler()
... next(a)
... next(d)
... for i in range(10):
... print(a.send(i), d.send(i))
0 0
1 2
3 6
6 12
10 20
15 30
21 42
28 56
36 72
45 90
我想这就是你想要的:
def doubler():
a = accumulator()
y = a.send(None)
x = yield 0
while True:
y = a.send(x)
x = yield 2 * y
这完全包装了 accumulator
实现,但您也可以使其可见并将其作为参数 a
传递给 doubler。
如果您需要与协程具有相同的接口(即具有 send
方法),那么 BrenBarn 的解决方案可能就这么简单。*
如果你可以有一个稍微不同的接口,那么高阶函数就更简单了:
def factor_wrapper(coroutine, factor):
next(coroutine)
return lambda x, c=coroutine, f=factor: f * c.send(x)
您将按如下方式使用它:
>>> a = accumulator()
>>> a2 = factor_wrapper(a, 2)
>>> print a2(1)
2
>>> print a2(2)
6
>>> print a2(3)
12
*实际上你 可以 削减几行使其总共 4 行,虽然并没有真正降低复杂性。
def doubler(a):
y = yield next(a)
while True:
y = yield (2 * a.send(y))
甚至更短...
def doubler(a, y=None):
while True:
y = yield 2 * a.send(y)
以上任意一种都可以按如下方式使用:
>>> a = accumulator()
>>> a2 = doubler(a)
>>> print a2.send(None) # Alternatively next(a2)
0
>>> print a2.send(1)
2
>>> print a2.send(2)
6
>>> print a2.send(3)
12