0

我正在使用 Python 3.6,您可以在其中很好地zip单独使用一种生成器来获得相同类型的多维生成器。以下面的例子为例,其中get_random_sequence是一个生成器,它产生一个无限的随机数序列来模拟股票市场上的一个单独的资产。

import random
from typing import Iterator

def get_random_sequence(start_value: float) -> Iterator[float]:
    value = start_value
    yield value

    while True:
        r = random.uniform(-.1, .1) * value
        value = value + r
        yield value

g = get_random_sequence(1.)
a = [next(g) for _ in range(5)]
print(a)
# [1.0, 1.015821868415922, 1.051470250712725, 0.9827564500218019, 0.9001851912863]

该生成器可以使用 Python 的zip函数轻松扩展,并yield from在具有任意数量资产的模拟市场上生成连续的资产值。

def get_market(no_assets: int = 10) -> Iterator[Sequence[float]]:
    rg = tuple(get_random_sequence(random.uniform(10., 60.)) for _ in range(no_assets))
    yield from zip(*rg)

gm = get_market(2)
b = [next(gm) for _ in range(5)]
print(b)
# [(55.20719435959121, 54.15552382961163), (51.64409510285255, 53.6327489348457), (50.16517363363749, 52.92881727359184), (48.8692976247231, 52.7090801870517), (52.49414777987645, 49.733746261206036)]

我喜欢这种方法的原因是使用yield from来避免必须显式构造n 个while True:资产的元组的循环。

我的问题是:当ped 生成器收到超过的值时,有没有办法以yield from类似的方式应用?zipsend()

考虑以下生成器,它产生无限序列中连续值的比率。

from typing import Optional, Generator

def ratio_generator() -> Generator[float, Optional[float], None]:
    value_last = yield
    value = yield
    while True:
        ratio = 0. if value_last == 0. else value / value_last
        value_last = value
        value = yield ratio

gr = ratio_generator()
next(gr)    # move to the first yield
g = get_random_sequence(1.)
a = []
for _v in g:
    _r = gr.send(_v)
    if _r is None:
        # two values are required for a ratio
        continue
    a.append(_r)
    if len(a) >= 5:
        break
print(a)
# [1.009041186223442, 0.9318419861800313, 1.0607677437816718, 0.9237896996817375, 0.9759635921282439]

zip不幸的是,我能想出的“”这个生成器的最佳方法根本不涉及yield from......而是while True:上面提到的丑陋解决方案。

def ratio_generator_multiple(no_values: int) -> Generator[Sequence[float], Optional[Sequence[float]], None]:
    gs = tuple(ratio_generator() for _ in range(no_values))
    for each_g in gs:
        next(each_g)

    values = yield
    ratios = tuple(g.send(v) for g, v in zip(gs, values))

    while True: # :(
        values = yield None if None in ratios else ratios
        ratios = tuple(g.send(v) for g, v in zip(gs, values))

rgm = ratio_generator_multiple(2)
next(rgm)    # move to the first yield
gm = get_market(2)
b = []
for _v in gm:
    _r = rgm.send(_v)
    if _r is None:
        # two values are required for a ratio
        continue
    b.append(_r)
    if len(b) >= 5:
        break
print(b)
# [(1.0684036496767984, 1.0531433541856687), (1.0279604693226763, 1.0649271401851732), (1.0469406709985847, 0.9350856571355237), (0.9818403001921499, 1.0344633443394962), (1.0380945284830183, 0.9081599684720663)]

有没有办法做类似的事情,values = yield from zip(*(g.send(v) for g, v in zip(generators, values)))所以我仍然可以yield fromzip没有 的 ped 发电机上使用while True:?(给定的示例不起作用,因为它不会values用左侧的 刷新右侧的values。)

我意识到这更像是一个审美问题。不过还是很高兴知道...

4

0 回答 0