74

Python 3.2 で以下のコードがあり、Python 2.7 で実行したかったのです。私はそれを変換しました(missing_elements両方のバージョンにコードを入れました)が、それが最も効率的な方法であるかどうかはわかりません。基本的に以下のように関数yield fromの上半分と下半分の2つの呼び出しがあるとどうなるでしょうか?親の再帰関数が呼び出しで機能し、両方の半分を一緒に使用できるようmissing_elementに、2 つの半分 (上半分と下半分) のエントリが 1 つのリストに追加されますか?yield from

def missing_elements(L, start, end):  # Python 3.2
    if end - start <= 1: 
        if L[end] - L[start] > 1:
            yield from range(L[start] + 1, L[end])
        return

index = start + (end - start) // 2

# is the lower half consecutive?
consecutive_low =  L[index] == L[start] + (index - start)
if not consecutive_low:
    yield from missing_elements(L, start, index)

# is the upper part consecutive?
consecutive_high =  L[index] == L[end] - (end - index)
if not consecutive_high:
    yield from missing_elements(L, index, end)

def main():
    L = [10, 11, 13, 14, 15, 16, 17, 18, 20]
    print(list(missing_elements(L, 0, len(L)-1)))
    L = range(10, 21)
    print(list(missing_elements(L, 0, len(L)-1)))

def missing_elements(L, start, end):  # Python 2.7
    return_list = []                
    if end - start <= 1: 
        if L[end] - L[start] > 1:
            return range(L[start] + 1, L[end])

    index = start + (end - start) // 2

    # is the lower half consecutive?
    consecutive_low =  L[index] == L[start] + (index - start)
    if not consecutive_low:
        return_list.append(missing_elements(L, start, index))

    # is the upper part consecutive?
    consecutive_high =  L[index] == L[end] - (end - index)
    if not consecutive_high:
        return_list.append(missing_elements(L, index, end))
    return return_list
4

6 に答える 6

94
于 2013-07-10T21:41:55.087 に答える
6

それらを for ループに置き換えます。

yield from range(L[start] + 1, L[end])

==>

for i in range(L[start] + 1, L[end]):
    yield i

要素についても同じ:

yield from missing_elements(L, index, end)

==>

for el in missing_elements(L, index, end):
    yield el
于 2013-07-10T21:42:13.260 に答える
4

Python 2 構文バージョンを構築するために、 pep-380の定義を使用するのはどうでしょうか。

ステートメント:

RESULT = yield from EXPR

意味的には次と同等です。

_i = iter(EXPR)
try:
    _y = next(_i)
except StopIteration as _e:
    _r = _e.value
else:
    while 1:
        try:
            _s = yield _y
        except GeneratorExit as _e:
            try:
                _m = _i.close
            except AttributeError:
                pass
            else:
                _m()
            raise _e
        except BaseException as _e:
            _x = sys.exc_info()
            try:
                _m = _i.throw
            except AttributeError:
                raise _e
            else:
                try:
                    _y = _m(*_x)
                except StopIteration as _e:
                    _r = _e.value
                    break
        else:
            try:
                if _s is None:
                    _y = next(_i)
                else:
                    _y = _i.send(_s)
            except StopIteration as _e:
                _r = _e.value
                break
RESULT = _r

ジェネレーターでは、ステートメント:

return value

意味的に同等です

raise StopIteration(value)

exceptただし、現在のところ、返されるジェネレーター内の句によって例外をキャッチすることはできません。

StopIteration 例外は、次のように定義されているかのように動作します。

class StopIteration(Exception):

    def __init__(self, *args):
        if len(args) > 0:
            self.value = args[0]
        else:
            self.value = None
        Exception.__init__(self, *args)
于 2016-08-15T14:44:18.967 に答える
3

yield fromPython 2.x でPython 3.x 構造をエミュレートする方法を見つけたと思います。効率的ではなく、少しハックですが、次のとおりです。

import types

def inline_generators(fn):
    def inline(value):
        if isinstance(value, InlineGenerator):
            for x in value.wrapped:
                for y in inline(x):
                    yield y
        else:
            yield value
    def wrapped(*args, **kwargs):
        result = fn(*args, **kwargs)
        if isinstance(result, types.GeneratorType):
            result = inline(_from(result))
        return result
    return wrapped

class InlineGenerator(object):
    def __init__(self, wrapped):
        self.wrapped = wrapped

def _from(value):
    assert isinstance(value, types.GeneratorType)
    return InlineGenerator(value)

使用法:

@inline_generators
def outer(x):
    def inner_inner(x):
        for x in range(1, x + 1):
            yield x
    def inner(x):
        for x in range(1, x + 1):
            yield _from(inner_inner(x))
    for x in range(1, x + 1):
        yield _from(inner(x))

for x in outer(3):
    print x,

出力を生成します:

1 1 1 2 1 1 2 1 2 3

多分誰かがこれが役立つと思うでしょう。

既知の問題: send() および PEP 380 で説明されているさまざまなコーナー ケースのサポートがありません。これらは追加される可能性があり、機能するようになったらエントリを編集します。

于 2013-09-29T03:06:52.980 に答える
0

リソース コンテキストを ( python-resourcesモジュールを使用して) 使用することが、Python 2.7 でサブジェネレーターを実装するための洗練されたメカニズムであることがわかりました。都合のよいことに、私はすでにリソース コンテキストを使用していました。

Python 3.3 の場合:

@resources.register_func
def get_a_thing(type_of_thing):
    if type_of_thing is "A":
        yield from complicated_logic_for_handling_a()
    else:
        yield from complicated_logic_for_handling_b()

def complicated_logic_for_handling_a():
    a = expensive_setup_for_a()
    yield a
    expensive_tear_down_for_a()

def complicated_logic_for_handling_b():
    b = expensive_setup_for_b()
    yield b
    expensive_tear_down_for_b()

Python 2.7 では、次のようになります。

@resources.register_func
def get_a_thing(type_of_thing):
    if type_of_thing is "A":
        with resources.complicated_logic_for_handling_a_ctx() as a:
            yield a
    else:
        with resources.complicated_logic_for_handling_b_ctx() as b:
            yield b

@resources.register_func
def complicated_logic_for_handling_a():
    a = expensive_setup_for_a()
    yield a
    expensive_tear_down_for_a()

@resources.register_func
def complicated_logic_for_handling_b():
    b = expensive_setup_for_b()
    yield b
    expensive_tear_down_for_b()

複雑なロジック操作では、リソースとしての登録のみが必要であることに注意してください。

于 2014-10-03T15:40:14.697 に答える