programing

실제로 Python 3.3에서 "유효율" 구문의 주요 용도는 무엇입니까?

goodsources 2022. 11. 20. 12:21
반응형

실제로 Python 3.3에서 "유효율" 구문의 주요 용도는 무엇입니까?

PEP 380 때문에 머리를 싸매기가 힘들어요.

  1. what황상???yield from★★★★★★★★★★★★★★★★★?
  2. 전형적인 사용 사례는 무엇입니까?
  3. 왜 마이크로 스레드와 비교됩니까?

지금까지 발전기를 사용해 왔지만, 코루틴(PE-342에서 도입)을 실제로 사용한 적은 없습니다.몇 가지 유사점에도 불구하고 제너레이터와 코루틴은 기본적으로 두 가지 다른 개념입니다.새로운 구문을 이해하기 위해서는 (제너레이터뿐만 아니라) 코루틴을 이해하는 것이 중요합니다.

IMHO 코루틴은 가장 잘 알려지지 않은 Python의 특징이며, 대부분의 책은 이것을 쓸모없고 재미없어 보이게 한다.


좋은 답변 감사합니다만, agf와 데이비드 비즐리 프레젠테이션에 대한 그의 코멘트 덕분에 특별한 감사를 드립니다.

★★★★★★★★★★★★★★★★★★★★★★★★★★★라고 yield from g for v in g: yield v 심지어 무엇을 정당하게 평가하지도 않고yield from모든 것이 중요합니다. 말하자면, 것이 다 그렇다는 이다.yield from 하면 ''이 .for가 되는 는, 「이러프」를 추가하는 되지 않습니다.yield fromPython 2.x의 경우

what?yield from는, 발신자와 서브 패킷간에 투과적인 쌍방향 접속을 확립하고 있는 것을 나타내고 있습니다.

  • 이 접속은 생성되는 요소뿐만 아니라 모든 것을 올바르게 전파한다는 점에서 "투과적"입니다(예: 예외가 전파됨).

  • 이 접속은 데이터를 제너레이터와 주고받을 수 있다는 점에서 "양방향"입니다.

(TCP에 대해서라면,클라이언트의 소켓을 일시적으로 절단해, 다른 서버 소켓에 재접속합니다」라고 하는 의미일 가능성이 있습니다).

그나저나 생성기에 데이터를 보내는 것이 무엇을 의미하는지 잘 모르겠다면 모든 것을 버리고 코루틴에 대해 먼저 읽어야 한다. 코루틴은 매우 유용하지만(서브루틴과 대조된다), 안타깝게도 Python에서는 잘 알려져 있지 않다.Dave Beazley의 Coroutines에 대한 Curious Course는 훌륭한 시작이다.슬라이드 24-33을 읽고 빠른 입문서를 확인하십시오.

수율을 사용하여 제너레이터에서 데이터 읽기

def reader():
    """A generator that fakes a read from a file, socket, etc."""
    for i in range(4):
        yield '<< %s' % i

def reader_wrapper(g):
    # Manually iterate over data produced by reader
    for v in g:
        yield v

wrap = reader_wrapper(reader())
for i in wrap:
    print(i)

# Result
<< 0
<< 1
<< 2
<< 3

를 수동으로 이 아니라reader() 돼요.yield from바로 그거에요.

def reader_wrapper(g):
    yield from g

그게 먹혀들었고 코드 한 줄도 없앴어요그리고 아마도 그 의도가 조금 더 명확할 것이다(혹은 그렇지 않을 것이다).하지만 삶은 변하지 않아요.

제1부 수율을 이용한 발전기(코루틴) 데이터 전송

이제 좀 더 흥미로운 것을 해 봅시다.writer송신된 데이터를 받아들여 소켓, fd 등에 기입합니다.

def writer():
    """A coroutine that writes data *sent* to it to fd, socket, etc."""
    while True:
        w = (yield)
        print('>> ', w)

이제 문제는 래퍼 함수가 라이터에 데이터를 보내는 것을 어떻게 처리해야 하는가 입니다. 그러면 래퍼로 전송되는 모든 데이터가 투명하게writer()

def writer_wrapper(coro):
    # TBD
    pass

w = writer()
wrap = writer_wrapper(w)
wrap.send(None)  # "prime" the coroutine
for i in range(4):
    wrap.send(i)

# Expected result
>>  0
>>  1
>>  2
>>  3

래퍼에 송신되는 데이터를 (분명히) 받아 들여야 하며, 래퍼에 의해 처리되어야 합니다.StopIterationfor 루프가 모두 사용되었을 때.그냥 하는 게 분명해for x in coro: yield x 하다, 이렇게 수 있는 요.여기 동작하는 버전이 있습니다.

def writer_wrapper(coro):
    coro.send(None)  # prime the coro
    while True:
        try:
            x = (yield)  # Capture the value that's sent
            coro.send(x)  # and pass it to the writer
        except StopIteration:
            pass

아니면 이렇게 할 수도 있어요.

def writer_wrapper(coro):
    yield from coro

이렇게 하면 6줄의 코드가 절약되어 훨씬 읽기 쉬워지고 동작도 쉬워집니다.마법!

제2부 - 예외 처리에서 발전기 수율에 데이터 전송

좀 더 복잡하게 합시다.만약 우리 작가가 예외를 다루어야 한다면?를 들어, '우리'라고 .writer 취급하다SpamException 그것은 인쇄하다***마주치게 되면요.

class SpamException(Exception):
    pass

def writer():
    while True:
        try:
            w = (yield)
        except SpamException:
            print('***')
        else:
            print('>> ', w)

바꾸면 해요?writer_wrapper★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.

# writer_wrapper same as above

w = writer()
wrap = writer_wrapper(w)
wrap.send(None)  # "prime" the coroutine
for i in [0, 1, 2, 'spam', 4]:
    if i == 'spam':
        wrap.throw(SpamException)
    else:
        wrap.send(i)

# Expected Result
>>  0
>>  1
>>  2
***
>>  4

# Actual Result
>>  0
>>  1
>>  2
Traceback (most recent call last):
  ... redacted ...
  File ... in writer_wrapper
    x = (yield)
__main__.SpamException

아, 아, 아, 아, 아, 아, 아, 아, 아, 안 x = (yield)예외만 제기하면 모든 것이 완전히 중단됩니다.(Sub-generator 합니다.writer)

def writer_wrapper(coro):
    """Works. Manually catches exceptions and throws them"""
    coro.send(None)  # prime the coro
    while True:
        try:
            try:
                x = (yield)
            except Exception as e:   # This catches the SpamException
                coro.throw(e)
            else:
                coro.send(x)
        except StopIteration:
            pass

이거 되는구나.

# Result
>>  0
>>  1
>>  2
***
>>  4

하지만 이것도 마찬가지야!

def writer_wrapper(coro):
    yield from coro

yield from는 값을 전송하거나 서브패킷에 값을 던지는 작업을 투과적으로 처리합니다.

그러나 이것은 여전히 모든 코너 케이스를 커버하는 것은 아닙니다.외부 제너레이터가 닫히면 어떻게 됩니까?하위 생성기가 값을 반환하는 경우(예, Python 3.3+에서는 생성기가 값을 반환할 수 있음), 반환 값은 어떻게 전파해야 합니까?구석진 사건을 투명하게 처리해 주는 건 정말 인상적이에요. yield from마법처럼 작동하고 모든 사건을 처리할 수 있어요

저는 개인적으로yield from쌍방향의 특성을 명확하게 하지 않기 때문에 키워드 선택이 적절하지 않습니다.다른 키워드가 제안되었습니다(예:delegate하지만 새로운 키워드를 언어에 추가하는 것이 기존 키워드를 결합하는 것보다 훨씬 더 어렵기 때문에 거절당했다.

「아, 아, 아, 아, 아」라고 하는 것이 가장 좋습니다.yield from발신자와 서브패키지 사이의 a로 간주됩니다.

참고 자료:

  1. PEP 380 - 서브제너레이터에 위임하기 위한 구문(유잉) [v3.3, 2009-02-13]
  2. PEP 342 - Enhanced Generator(GvR, Eby) 경유 Coroutine [v2.5, 2005-05-10]

"수익률"이 유용한 상황은 무엇입니까?

다음과 같은 루프가 있는 모든 상황은 다음과 같습니다.

for x in subgenerator:
  yield x

한 바와 같이 PEP의 특히 PEP의 적절한 처리가 ..throw()/.send()/.close()PEP 342에 의해 도입된 메커니즘.이것을 올바르게 실시하려면 , 다소 복잡한 코드가 필요합니다.

전형적인 사용 사례는 무엇입니까?

재귀 데이터 구조에서 정보를 추출하는 것을 고려합니다.예를 들어 트리 내의 모든 리프 노드를 가져오고 싶다고 합시다.

def traverse_tree(node):
  if not node.children:
    yield node
  for child in node.children:
    yield from traverse_tree(child)

은 '이것보다 더 중요한 것은 '이것'이 될 yield from제너레이터 코드를 리팩터링하는 간단한 방법은 없었습니다.다음과 같은 (무분별한) 제너레이터가 있다고 가정합니다.

def get_list_values(lst):
  for item in lst:
    yield int(item)
  for item in lst:
    yield str(item)
  for item in lst:
    yield float(item)

이제 이러한 루프를 인수분해하여 개별 생성기로 만듭니다.yield from정말 하고 싶은지 두 번 생각할 정도로 추하다.★★★★★★★★★★★★★★★★ yield from을 사용법

def get_list_values(lst):
  for sub in [get_list_values_as_int, 
              get_list_values_as_str, 
              get_list_values_as_float]:
    yield from sub(lst)

왜 마이크로 스레드와 비교됩니까?

PEP의 이 섹션에서 말하는 것은 모든 발전기가 각각의 분리된 실행 컨텍스트를 가지고 있다는 것입니다.이 때, 제너레이터-이터레이터와 발신자 사이에 실행이 전환됩니다.yield ★★★★★★★★★★★★★★★★★」__next__()이는 각각 스레드와 유사하며 운영체제는 실행 컨텍스트(스택, 레지스터 등)와 함께 실행 스레드를 수시로 전환합니다.

이 효과는 다음과 같습니다.제너레이터 반복기와 발신자 모두 동시에 실행 상태로 진행되며 실행이 인터리빙됩니다.예를 들어 제너레이터가 어떤 계산을 수행하고 호출자가 결과를 출력하면 결과가 나오는 즉시 결과를 볼 수 있습니다.이것은 동시성의 한 형태입니다.

는 특별한.yield from만만 python python, Python 의 python의 python python python python python python python python python python python python python python python python.

를 호출하는 라면 어디서든 를 사용하여 을 해야 .yield ":for v in inner_generator: yield vPEP가 지적한 바와 같이 여기에는 대부분의 사람들이 무시하는 미묘한 복잡성이 있다.의 흐름 (「」등)throw()PEP의 입니다. 구문 " " " "yield from inner_generator됩니다.for루프를 실행합니다.하지만 통사당뿐만이 아닙니다.합니다.for이 되는 것은 사람들이 하고, 올바른행동을 .설탕"이 되는 것은 사람들이 그것을 사용하도록 장려하고, 따라서 올바른 행동을 하도록 한다.

토론 스레드의 다음 메시지는 다음과 같은 복잡성에 대해 설명합니다.

PEP 342에 의해 도입된 추가 제너레이터 기능으로 인해 Greg의 PEP에서 설명한 바와 같이 단순한 반복은 send()와 throw()를 올바르게 지원하지 않습니다.send()와 throw()를 지원하는 데 필요한 체조는 실제로 분해할 때 그리 복잡하지 않지만 사소한 것도 아닙니다.

발전기가 일종의 가성애라는 것을 관찰하는 것 외에는 마이크로 스레드와의 비교에 대해 말할 수 없습니다.서스펜드 제너레이터를 통해 값을 전송하는 스레드로 간주할 수 있습니다.yield소비자에게 전달됩니다.실제 구현은 이와 전혀 다를 수 있지만(또한 실제 구현은 Python 개발자들에게 분명 큰 관심사입니다), 이것은 사용자와 관련이 없습니다.

★★★★★yield from구문은 스레드화 측면에서 언어에 추가 기능을 추가하지 않습니다.기존 기능을 올바르게 사용하기 쉽게 할 뿐입니다.또는 보다 정확하게는 전문가가 작성한 복잡한 내부 발전기의 초보 소비자가 복잡한 기능을 끊지 않고 발전기를 쉽게 통과할 수 있도록 합니다.

이 될 입니다.yield from 예:에서 값을 .

def flatten(sequence):
    """flatten a multi level list or something
    >>> list(flatten([1, [2], 3]))
    [1, 2, 3]
    >>> list(flatten([1, [2], [3, [4]]]))
    [1, 2, 3, 4]
    """
    for element in sequence:
        if hasattr(element, '__iter__'):
            yield from flatten(element)
        else:
            yield element

print(list(flatten([1, [2], [3, [4]]])))

yield from으로 반복기를 방법으로 합니다.

# chain from itertools:
def chain(*iters):
    for it in iters:
        for item in it:
            yield item

# with the new keyword
def chain(*iters):
    for it in iters:
        yield from it

보시다시피 Python의 순수한 루프가 1개씩 제거됩니다.거의 그것뿐이지만, Python에서는 반복기를 체인으로 하는 것이 매우 일반적인 패턴입니다.

스레드는 기본적으로 완전히 랜덤한 지점에서 함수를 점프하여 다른 함수의 상태로 돌아갈 수 있는 기능입니다.스레드 슈퍼바이저는 이 작업을 매우 자주 하기 때문에 프로그램은 이러한 모든 기능을 동시에 실행하는 것으로 보입니다.문제는 포인트가 랜덤이기 때문에 문제가 있는 시점에서 슈퍼바이저가 기능을 정지하지 않도록 잠금을 사용해야 한다는 것입니다.

제너레이터는 이 점에서 스레드와 매우 유사합니다.할 수 지정됩니다).yield하거나 점프할 수 ( ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) 。이렇게 사용할 경우 생성기를 코루틴이라고 합니다.

자세한 내용은 Python의 Coroutine에 대한 이 훌륭한 튜토리얼을 읽어보십시오.

Asynchronous IO coroutine에 적용된 사용방법에서는yield from와 같은 행동을 하다await코루틴 함수로요둘 다 코루틴의 실행을 중지하기 위해 사용됩니다.

경우 버전(가 없는 Asyncio는 Python(3.5)을 지원합니다.async def/await코루틴을 사용하다 ★★★★★★★★★★★★★★★★★▼yield from더 이상 코루틴에는 필요 없습니다.

에서는 asyncio가 사용됩니다.yield from <sub-generator>는 앞의 답변에서 설명한 바와 같이 하위 항목을 반복할 때 다른 용도를 가지고 있습니다.

yield의지하다

yield from의지는 컬렉션을 수집으로 만들고 평평하게 만듭니다.

다음의 예를 확인해 주세요.

def yieldOnly():
    yield "A"
    yield "B"
    yield "C"

def yieldFrom():
    for i in [1, 2, 3]:
        yield from yieldOnly()

test = yieldFrom()
for i in test:
print(i)

콘솔에는 다음이 표시됩니다.

A
B
C
A
B
C
A
B
C

는 함수를 합니다.fixed_sum_digits6자리 숫자를 모두 열거한 제너레이터를 반환하여 자릿수의 합계가 20이 되도록 합니다.

def iter_fun(sum, deepness, myString, Total):
    if deepness == 0:
        if sum == Total:
            yield myString
    else:  
        for i in range(min(10, Total - sum + 1)):
            yield from iter_fun(sum + i,deepness - 1,myString + str(i),Total)

def fixed_sum_digits(digits, Tot):
    return iter_fun(0,digits,"",Tot) 

이 글을 쓰지 말고 .yield from효과적인 방법을 찾으면 알려주세요.

은 나무 방문은 나무 방문과 같은 경우라고 합니다.yield from코드를 심플하고 깔끔하게 만듭니다.

말하면, ★★★★★★★★★★★★★★★★★★★★.yield from는 반복기 함수의 테일 재귀 기능을 제공합니다.

yield from생성기가 비워질 때까지 생성기에서 산출한 후 다음 코드 을 계속 실행합니다.

예.

def gen(sequence):
    for i in sequence:
        yield i


def merge_batch(sub_seq):
    yield {"data": sub_seq}

def modified_gen(g, batch_size):
    stream = []
    for i in g:
        stream.append(i)
        stream_len = len(stream)
        if stream_len == batch_size:
            yield from merge_batch(stream)
            print("batch ends")
            stream = []
            stream_len = 0

다음을 수행합니다.

In [17]: g = gen([1,2,3,4,5,6,7,8,9,10])
In [18]: mg = modified_gen(g, 2)
In [19]: next(mg)
Out[19]: {'data': [1, 2]}

In [20]: next(mg)
batch ends
Out[20]: {'data': [3, 4]}

In [21]: next(mg)
batch ends
Out[21]: {'data': [5, 6]}

In [22]: next(mg)
batch ends
Out[22]: {'data': [7, 8]}

In [23]: next(mg)
batch ends
Out[23]: {'data': [9, 10]}

In [24]: next(mg)
batch ends
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
Input In [24], in <cell line: 1>()
----> 1 next(mg)

StopIteration: 

따라서, 에서 나오는 수율은 다른 제너레이터로부터 출력을 받아 일부 수정을 한 다음, 자체 출력을 제너레이터 자체로서 다른 제너레이터에 공급할 수 있습니다.

미미한 제 의견으로는, 이 제품이 다음 제품의 주요 사용 사례 중 하나라고 생각합니다.yield from

언급URL : https://stackoverflow.com/questions/9708902/in-practice-what-are-the-main-uses-for-the-yield-from-syntax-in-python-3-3

반응형