Python 협회 의 상세 한 용법 사용 과 예 를 자세히 설명 합 니 다.

13678 단어 Python협정
구법 적 으로 볼 때 협 정 은 생 성기 와 유사 하 며 모두 정의 체 에 yield 키 워드 를 포함 하 는 함수 입 니 다.그러나 협 정 에서 yield 는 표현 식 오른쪽(예 를 들 어 datum=yield)에 나타 나 값 을 산출 할 수도 있 고 산출 하지 않 을 수도 있 습 니 다.yield 키워드 뒤에 표현 식 이 없 으 면 생 성 기 는 None 를 산출 합 니 다.
협 정 은 호출 자 에서 데 이 터 를 받 을 수 있 지만 호출 자가 협 정 에 데 이 터 를 제공 하 는 것 은 next(...)함수 가 아 닌 send(datum)방법 을 사용 합 니 다.
==yield 키 워드 는 데 이 터 를 받 지 않 거나 전달 하지 않 아 도 됩 니 다.데이터 가 어떻게 흐 르 든 지 간 에 yield 는 프로 세 스 제어 도구 입 니 다.이 를 사용 하면 합작 식 다 중 임 무 를 실현 할 수 있 습 니 다.협 정 은 컨트롤 러 를 중심 스케줄 러 에 양보 하여 다른 협 정 을 활성화 할 수 있 습 니 다==
협정 생 성기 의 기본 행위
여기에 가장 간단 한 협정 코드 가 하나 있다.

def simple_coroutine():
  print('-> start')
  x = yield
  print('-> recived', x)

sc = simple_coroutine()

next(sc)
sc.send('zhexiao')
설명:
1.협 정 은 생 성기 함수 정 의 를 사용 합 니 다.정의 체 에 yield 키워드 가 있 습 니 다.
2.yield 는 표현 식 에서 사용 합 니 다.협 정 이 고객 에 게 서 만 데 이 터 를 받 으 면 산출 된 값 은 None―이 값 은 암시 적 으로 지정 되 어 있 습 니 다.yield 키워드 오른쪽 에 표현 식 이 없 기 때 문 입 니 다.
3.우선 next(...)함 수 를 호출 해 야 합 니 다.생 성기 가 아직 시작 되 지 않 았 기 때문에 yield 구문 에서 잠시 멈 추 지 않 았 기 때문에 처음에 데 이 터 를 보 낼 수 없습니다.
4.send 방법 을 호출 하여 yield 의 변 수 를 전달 한 다음 에 협 정 을 복원 하고 다음 yield 표현 식 으로 실행 되 거나 종 료 될 때 까지 아래 코드 를 계속 실행 합 니 다.
==주의:send 방법 은 해당 협 정 만 GEN 에 있 습 니 다.SUSPENDED 상태 에서 만 작 동 하기 때문에 next()방법 으로 협 정 을 활성화 하여 yield 표현 식 에서 멈 추거 나 sc.send(None)를 사용 할 수 있 습 니 다.효 과 는 next(sc)와 같 습 니 다.=
협정의 네 가지 상태:
협 정 은 네 가지 상태 중 하나 에 있 을 수 있다.현재 상 태 는 inspect.getgenerator state(...)함 수 를 사용 하여 확인 할 수 있 습 니 다.이 함 수 는 다음 문자열 중 하 나 를 되 돌려 줍 니 다.
1. GEN_CREATED:실행 을 기다 리 고 있 습 니 다.
2. GEN_런 닝:해석 기 실행 중
3. GEN_SUSPENED:yield 표현 식 에서 일시 정지
4. GEN_종료:실행 종료
==next(sc)함 수 를 가장 먼저 호출 합 니 다.

import inspect

def simple_coroutine(a):
  print('-> start')

  b = yield a
  print('-> recived', a, b)

  c = yield a + b
  print('-> recived', a, b, c)

# run 
sc = simple_coroutine(5)

next(sc)
sc.send(6) # 5, 6
sc.send(7) # 5, 6, 7

예시:협정 을 사용 하여 이동 평균 값 을 계산한다

def averager():
  total = 0.0
  count = 0
  avg = None

  while True:
    num = yield avg
    total += num
    count += 1
    avg = total/count

# run
ag = averager()
#     
print(next(ag))   # None

print(ag.send(10)) # 10
print(ag.send(20)) # 15
설명:
1.next(ag)함 수 를 호출 하면 협 정 은 yield 표현 식 으로 앞으로 실 행 됩 니 다.average 변수의 초기 값 인 None 를 생산 합 니 다.
2.이때 협 정 은 yield 표현 식 에서 잠시 중단 합 니 다.
3.send()를 사용 하여 협 정 을 활성화 하고 보 낸 값 을 num 에 부여 하 며 avg 의 값 을 계산 합 니 다.
4.print 를 사용 하여 yield 가 되 돌아 오 는 데 이 터 를 출력 합 니 다.
협정 과 이상 처 리 를 중지 하 다
협 정 에서 처리 되 지 않 은 이상 은 위로 거품 을 일 으 켜 next 함수 나 send 방법의 호출 자(즉 협 정 을 촉발 하 는 대상)에 게 전 달 됩 니 다.
==협 정 을 종료 하 는 방식:어떤 호루라기 값 을 보 내 협 정 을 종료 합 니 다.내 장 된 None 과 Ellipsis 등 상수 가 호루라기 값 으로 자주 사 용 됩 니 다==.
이상 을 명시 적 으로 협정 에 보내다
Python 2.5 부터 클 라 이언 트 코드 는 생 성기 대상 에서 두 가지 방법 을 호출 하여 이상 을 협의 에 명시 적 으로 보 낼 수 있 습 니 다.

generator.throw(exc_type[, exc_value[, traceback]])
생 성 기 는 일시 정 지 된 yield 표현 식 에서 지정 한 이상 을 던 집 니 다.생 성기 가 던 진 이상 을 처리 하면 코드 는 다음 yield 표현 식 으로 앞으로 실 행 됩 니 다.생산 된 값 은 generator.throw 방법 으로 되 돌아 오 는 값 이 됩 니 다.생 성기 가 던 진 이상 을 처리 하지 않 으 면 이상 이 위로 거품 을 일 으 켜 호출 자의 문맥 에 전 달 됩 니 다.
generator.close()
생 성 기 는 일시 정 지 된 yield 표현 식 에서 Generator Exit 이상 을 던 집 니 다.생 성기 가 이 이상 을 처리 하지 않 았 거나 StopIteration 이상 을 던 졌 다 면 호출 자 는 잘못 보고 하지 않 습 니 다.Generator Exit 이상 을 받 으 면 생 성 기 는 값 을 생산 할 수 없습니다.그렇지 않 으 면 해석 기 는 Runtime Error 이상 을 던 집 니 다.생 성기 가 던 진 다른 이상 은 위로 거품 을 일 으 켜 호출 자 에 게 전달 된다.
예외 처리 예시:

class DemoException(Exception):
  """
  custom exception
  """

def handle_exception():
  print('-> start')

  while True:
    try:
      x = yield
    except DemoException:
      print('-> run demo exception')
    else:
      print('-> recived x:', x)

  raise RuntimeError('this line should never run')

he = handle_exception()
next(he)
he.send(10) # recived x: 10
he.send(20) # recived x: 20

he.throw(DemoException) # run demo exception

he.send(40) # recived x: 40
he.close()
처리 할 수 없 는 이상 이 들 어 오 면 협 정 은 종 료 됩 니 다.

he.throw(Exception) # run demo exception
yield from 협회 의 반환 값 가 져 오기
반환 치 를 얻 기 위해 서 는 협 정 이 정상적으로 종료 되 어야 합 니 다.그리고 생 성기 대상 은 StopIteration 이상 을 던 지고 이상 대상 의 value 속성 은 되 돌아 오 는 값 을 저장 합 니 다.
==yield from 구 조 는 내부 에서 StopIteration 이상 을 자동 으로 포착 합 니 다.yield from 구조 에 있어 서 해석 기 는 StopIteration 이상 을 포착 할 뿐만 아니 라 value 속성의 값 을 yield from 표현 식 의 값 으로 바 꿉 니 다.
기본 용법
==생 성기 gen 에서 yield from subgen()을 사용 할 때 subgen 은 제어 권 을 얻 고 생산 된 값 을 gen 의 호출 자 에 게 전달 합 니 다.즉,호출 자 는 subgen 을 직접 제어 할 수 있 습 니 다.이와 동시에 gen 은 차단 되 어 subgen 이 종 료 될 때 까지 기 다 립 니 다==.
다음 두 함수 의 역할 은 마찬가지 로 yield from 을 사용 하여 더욱 간결 합 니 다.

def gen():
  for c in 'AB':
    yield c

print(list(gen()))

def gen_new():
  yield from 'AB'

print(list(gen_new()))

==yield from x 표현 식 이 x 대상 에 게 하 는 첫 번 째 일 은 iter(x)를 호출 하여 교체 기 를 가 져 오 는 것 입 니 다.따라서 x 는 교체 가능 한 대상 이 될 수 있 습 니 다.이것 은 yield from 의 가장 기본 적 인 용법 일 뿐 입 니 다.=
yield from 고급 용법
==yield from 의 주요 기능 은 양 방향 통 로 를 열 고 가장 바깥쪽 의 호출 자 와 가장 안쪽 의 서브 생 성 기 를 연결 하 는 것 입 니 다.그러면 두 사람 은 직접 발송 하고 생산 할 수 있 으 며 이상 을 직접 전달 할 수 있 습 니 다.중간 에 있 는 협의 과정 에 이상 을 처리 하 는 모델 코드 를 대량으로 추가 하지 않 아 도 됩 니 다.=
전문 용어
  • 위임 생 성기:yield from 표현 식 의 생 성기 함 수 를 포함 합 니 다
  • 4.567917.자 생 성기:yield from 에서 얻 은 생 성기.도시

    설명:
    1.위임 생 성 기 는 yield from 표현 식 에서 잠시 멈 출 때 호출 자 는 하위 생 성 기 에 데 이 터 를 직접 보 낼 수 있 습 니 다.
    2.서브 생 성 기 는 생산 된 값 을 호출 자 에 게 보 냅 니 다.
    3.하위 생 성기 가 돌아 오 면 해석 기 는 StopIteration 이상 을 던 지고 반환 값 을 이상 대상 에 추가 합 니 다.이때 위임 생 성 기 는 회 복 됩 니 다.
    고급 예시
    
    from collections import namedtuple
    
    ResClass = namedtuple('Res', 'count average')
    
    #     
    def averager():
      total = 0.0
      count = 0
      average = None
    
      while True:
        term = yield
        if term is None:
          break
        total += term
        count += 1
        average = total / count
    
      return ResClass(count, average)
    
    
    #      
    def grouper(storages, key):
      while True:
        #   averager()    
        storages[key] = yield from averager()
    
    
    #      
    def client():
      process_data = {
        'boys_2': [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
        'boys_1': [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46]
      }
    
      storages = {}
      for k, v in process_data.items():
        #     
        coroutine = grouper(storages, k)
    
        #     
        next(coroutine)
    
        #        
        for dt in v:
          coroutine.send(dt)
    
        #     
        coroutine.send(None)
      print(storages)
    
    # run
    client()
    설명:
    1.외부 for 순환 은 매번 교체 할 때마다 grouper 인 스 턴 스 를 새로 만 들 고 coroutine 변 수 를 할당 합 니 다.grouper 는 위임 생 성기 입 니 다.
    2.next(coroutine)를 호출 하고 생 성기 grouper 를 미리 할당 합 니 다.이 때 while True 순환 에 들 어가 서 하위 생 성기 averager 를 호출 한 후 yield from 표현 식 에서 잠시 멈 춥 니 다.
    3.내부 for 순환 호출 coroutine.send(value),하위 생 성기 averager 에 직접 값 을 전달 합 니 다.또한,현재 grouper 인 스 턴 스(coroutine)는 yield from 표현 식 에서 일시 정지 합 니 다.
    4.내부 순환 이 끝 난 후에 도 grouper 인 스 턴 스 는 yield from 표현 식 에서 중단 되 었 습 니 다.따라서 grouper 함수 정의 체 에서 results[key]로 값 을 부여 하 는 문 구 는 아직 실행 되 지 않 았 습 니 다.
    5.coroutine.send(None)는 averager 하위 생 성 기 를 종료 합 니 다.하위 생 성 기 는 StopIteration 이상 을 던 지고 되 돌아 오 는 데 이 터 를 이상 대상 의 value 에 포함 시 킵 니 다.yield from 은 StopIteration 이상 을 직접 캡 처 하여 이상 대상 의 value 를 results[key]에 할당 할 수 있 습 니 다.
    yield from 의 의미
    4.567917.서브 생 성기 가 생산 한 값 은 모두 위임 생 성기 의 호출 자(즉 클 라 이언 트 코드)에 게 직접 전 달 됩 니 다4.567917.send()방법 으로 위임 생 성기 에 보 내 는 값 은 모두 하위 생 성기 에 직접 전달 합 니 다.보 낸 값 이 None 이면 하위 생 성기 의 next()방법 을 호출 합 니 다.보 낸 값 이 None 가 아니라면 하위 생 성기 의 send()방법 을 호출 합 니 다.호출 된 방법 이 StopIteration 이상 을 던 지면 위임 생 성 기 는 다시 실 행 됩 니 다.다른 어떤 이상 도 위로 거품 을 일 으 켜 위임 생 성기 에 전달 된다
  • 생 성기 가 종 료 될 때 생 성기(또는 하위 생 성기)의 return expr 표현 식 은 StopIteration(expr)이상 투 자 를 촉발 합 니 다
  • yield from 표현 식 의 값 은 하위 생 성기 가 종 료 될 때 StopIteration 이상 에 게 전 달 된 첫 번 째 매개 변수 입 니 다
  • 위임 생 성기 에 들 어 가 는 이상,Generator Exit 를 제외 하고 모두 하위 생 성기 에 전달 하 는 throw()방법.throw()방법 을 호출 할 때 StopIteration 이상 을 던 지면 위임 생 성 기 는 다시 실 행 됩 니 다.StopIteration 이외 의 이상 은 위로 거품 을 일 으 켜 위임 생 성기 에 전 달 됩 니 다.
  • Generator Exit 이상 을 위임 생 성기 에 전송 하거나 위임 생 성기 에서 close()방법 을 호출 하면 하위 생 성기 에서 close()방법 을 호출 합 니 다.있 으 면.close()방법 을 호출 하여 이상 하 게 던 지면 이상 이 위로 거품 을 일 으 켜 위임 생 성기 에 전 달 됩 니 다.그렇지 않 으 면,위임 생 성 기 는 Generator Exit 이상 을 던 집 니 다
  • 사용 사례
    협 정 은 많은 알고리즘 을 자 연 스 럽 게 표현 할 수 있다.예 를 들 어 시 뮬 레이 션,게임,비동기 I/O,그리고 다른 이벤트 구동 형 프로 그래 밍 형식 이나 협력 식 다 중 태 스 크 등 이다.협 정 은 asyncio 패키지 의 기초 구축 입 니 다.시 뮬 레이 션 시스템 을 통 해 스 레 드 대신 협 정 을 어떻게 사용 하 는 지 설명 할 수 있다.
    시 뮬 레이 션 분야 에서 프로 세 스 라 는 용 어 는 모델 의 특정한 실체 활동 을 가리 키 며 운영 체제 의 프로 세 스 와 무관 합 니 다.시 뮬 레이 션 시스템 의 한 프로 세 스 는 운영 체제 의 한 프로 세 스 를 사용 하여 이 루어 질 수 있 지만 보통 하나의 스 레 드 나 하나의 협 정 을 사용 하여 이 루어 집 니 다.
    택시
    
    import collections
    
    # time              ,
    # proc              ,
    # action            。
    Event = collections.namedtuple('Event', 'time proc action')
    
    
    def taxi_process(proc_num, trips_num, start_time=0):
      """
                 ,         
      :param proc_num:
      :param trips_num:
      :param start_time:
      :return:
      """
      time = yield Event(start_time, proc_num, 'leave garage')
    
      for i in range(trips_num):
        time = yield Event(time, proc_num, 'pick up people')
        time = yield Event(time, proc_num, 'drop off people')
    
      yield Event(time, proc_num, 'go home')
    
    # run
    t1 = taxi_process(1, 1)
    a = next(t1)  
    print(a)  # Event(time=0, proc=1, action='leave garage')
    b = t1.send(a.time + 6)
    print(b)  # Event(time=6, proc=1, action='pick up people')
    c = t1.send(b.time + 12)
    print(c)  # Event(time=18, proc=1, action='drop off people')
    d = t1.send(c.time + 1)
    print(d)  # Event(time=19, proc=1, action='go home')
    아 날로 그 콘 솔 에서 3 개의 택시 이 보 를 제어 하 다.
    
    import collections
    import queue
    import random
    
    # time              ,
    # proc              ,
    # action            。
    Event = collections.namedtuple('Event', 'time proc action')
    
    
    def taxi_process(proc_num, trips_num, start_time=0):
      """
                 ,         
      :param proc_num:
      :param trips_num:
      :param start_time:
      :return:
      """
      time = yield Event(start_time, proc_num, 'leave garage')
    
      for i in range(trips_num):
        time = yield Event(time, proc_num, 'pick up people')
        time = yield Event(time, proc_num, 'drop off people')
    
      yield Event(time, proc_num, 'go home')
    
    
    class SimulateTaxi(object):
      """
              
      """
    
      def __init__(self, proc_map):
        #         PriorityQueue   ,
        #       tuple  ,     tuple[0]   
        self.events = queue.PriorityQueue()
        # procs_map        ,  dict      
        self.procs = dict(proc_map)
    
      def run(self, end_time):
        """
               ,      
        :param end_time:
        :return:
        """
        for _, taxi_gen in self.procs.items():
          leave_evt = next(taxi_gen)
          self.events.put(leave_evt)
    
        #         
        simulate_time = 0
        while simulate_time < end_time:
          if self.events.empty():
            print('*** end of events ***')
            break
    
          #         
          current_evt = self.events.get()
          simulate_time, proc_num, action = current_evt
          print('taxi:', proc_num, ', at time:', simulate_time, ', ', action)
    
          #          
          proc_gen = self.procs[proc_num]
          next_simulate_time = simulate_time + self.compute_duration()
    
          try:
            next_evt = proc_gen.send(next_simulate_time)
          except StopIteration:
            del self.procs[proc_num]
          else:
            self.events.put(next_evt)
        else:
          msg = '*** end of simulation time: {} events pending ***'
          print(msg.format(self.events.qsize()))
    
      @staticmethod
      def compute_duration():
        """
                     
        :return:
        """
        duration_time = random.randint(1, 20)
        return duration_time
    
    
    #   3    ,         garage
    taxis = {i: taxi_process(i, (i + 1) * 2, i * 5)
         for i in range(3)}
    
    #     
    st = SimulateTaxi(taxis)
    st.run(100)
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기