Python 협회 의 상세 한 용법 사용 과 예 를 자세히 설명 합 니 다.
협 정 은 호출 자 에서 데 이 터 를 받 을 수 있 지만 호출 자가 협 정 에 데 이 터 를 제공 하 는 것 은 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 의 주요 기능 은 양 방향 통 로 를 열 고 가장 바깥쪽 의 호출 자 와 가장 안쪽 의 서브 생 성 기 를 연결 하 는 것 입 니 다.그러면 두 사람 은 직접 발송 하고 생산 할 수 있 으 며 이상 을 직접 전달 할 수 있 습 니 다.중간 에 있 는 협의 과정 에 이상 을 처리 하 는 모델 코드 를 대량으로 추가 하지 않 아 도 됩 니 다.=
전문 용어
설명:
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 이상 을 던 지면 위임 생 성 기 는 다시 실 행 됩 니 다.다른 어떤 이상 도 위로 거품 을 일 으 켜 위임 생 성기 에 전달 된다
협 정 은 많은 알고리즘 을 자 연 스 럽 게 표현 할 수 있다.예 를 들 어 시 뮬 레이 션,게임,비동기 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)
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Python의 None과 NULL의 차이점 상세 정보그래서 대상 = 속성 + 방법 (사실 방법도 하나의 속성, 데이터 속성과 구별되는 호출 가능한 속성 같은 속성과 방법을 가진 대상을 클래스, 즉 Classl로 분류할 수 있다.클래스는 하나의 청사진과 같아서 하나의 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.