Python의 Yield 및 Generator에 대한 자세한 소개
이 글은 주로 Python의 Yield와 Generator 관련 정보를 얕은 것부터 더 깊은 것까지 설명합니다. 글의 소개는 매우 자세하며 필요한 모든 사람이 참조할 수 있는 내용이 있습니다.
머리말
이 글에서는 어떤 제너레이터, 어떻게 생성하는지 등의 내용을 포함하여 간단한 것부터 깊은 것까지 Yield와 Generator를 자세히 소개합니다. 발전기 및 발전기 기능, 발전기의 기본 및 고급 응용 시나리오, 발전기 사용 시 주의 사항입니다. 이 글에는 Enhanced Generator나 pep342 관련 내용이 포함되어 있지 않습니다. 이 부분은 나중에 소개하겠습니다.
생성기 기본
파이썬의 함수 정의에서 항복 표현식이 나타나면 실제로 정의된 것은 생성기입니다. 함수이며, 이 generator function
호출의 반환 값은 생성기입니다. 이 일반적인 함수 호출은 다릅니다. 예:
def gen_generator(): yield 1 def gen_value(): return 1 if __name__ == '__main__': ret = gen_generator() print ret, type(ret) #<generator object gen_generator at 0x02645648> <type 'generator'> ret = gen_value() print ret, type(ret) # 1 <type 'int'>
위 코드에서 볼 수 있듯이 gen_generator
함수는 생성기 인스턴스를 반환합니다.
generator에는 다음과 같은 Special이 있습니다.
•__iter__
을 구현해야 하는 반복자 프로토콜을 따르고 다음 인터페이스
•여러 번 입력할 수 있으며 여러 번 반환하면 일시 중지될 수 있습니다. 함수 본문의 코드 실행
테스트 코드를 살펴보겠습니다.
>>> def gen_example(): ... print 'before any yield' ... yield 'first yield' ... print 'between yields' ... yield 'second yield' ... print 'no yield anymore' ... >>> gen = gen_example() >>> gen.next() # 第一次调用next before any yield 'first yield' >>> gen.next() # 第二次调用next between yields 'second yield' >>> gen.next() # 第三次调用next no yield anymore Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteratio
gen 예제 메서드를 호출하면 아무것도 출력되지 않습니다. 본문 코드가 아직 실행을 시작하지 않았습니다. 제너레이터의 다음 메소드가 호출되면 제너레이터는 항복 표현식을 실행하고, 항복 표현식의 내용을 반환한 다음 이 위치에서 일시 중지(중지)하므로 next에 대한 첫 번째 호출은 첫 번째 문장을 인쇄하고 "를 반환합니다. 첫 번째 수확량". 일시 중지한다는 것은 다음 메서드 호출이 재개될 때까지 메서드의 지역 변수, 포인터 정보 및 실행 환경이 저장된다는 의미입니다. next를 두 번째로 호출한 후 마지막 항복에서 일시 중지됩니다. next()
메서드가 다시 호출되면 StopIteration 예외가 발생합니다.
for 문은 StopIteration 예외를 자동으로 포착할 수 있기 때문에 생성기(기본적으로 모든 반복자)의 더 일반적인 방법은 이를 루프에서 사용하는 것입니다.
def generator_example(): yield 1 yield 2 if __name__ == '__main__': for e in generator_example(): print e # output 1 2
생성기는 다음에 의해 생성됩니다. 제너레이터 함수는 일반 함수와 어떻게 다른가요?
(1) 함수는 매번 첫 번째 줄부터 실행되고, 제너레이터는 마지막 Yield 시작부터 실행됩니다.
(2) 함수 호출은 한 번에 하나의 값(세트)을 반환하는 반면, 생성기는
을 여러 번 반환할 수 있습니다. (3) 함수는 수없이 반복적으로 호출될 수 있지만
함수에서 Yield를 사용한 후 함수를 호출하는 것은 생성기를 생성하는 방법입니다. 또 다른 일반적인 방법은 generator expression
을 사용하는 것입니다. 예:
>>> gen = (x * x for x in xrange(5)) >>> print gen <generator object <genexpr> at 0x02655710>
발전기 애플리케이션
발전기 기본 애플리케이션
생성기를 사용하는 가장 중요한 이유는 모든 반환 값을 한 번에 생성하는 대신 요청에 따라 결과를 생성하고 "반환"할 수 있다는 것입니다. 게다가 때로는 "모든 반환 값"을 전혀 알 수 없습니다. .
예를 들어 다음 코드의 경우
RANGE_NUM = 100 for i in [x*x for x in range(RANGE_NUM)]: # 第一种方法:对列表进行迭代 # do sth for example print i for i in (x*x for x in range(RANGE_NUM)): # 第二种方法:对generator进行迭代 # do sth for example print i
위 코드에서 두 for 문의 출력은 동일합니다. 코드는 문자 그대로 대괄호와 소문자를 의미합니다. 괄호의 차이점. 그러나 이 차이점은 매우 다릅니다. 첫 번째 메서드는 목록을 반환하고 두 번째 메서드는 생성기 개체를 반환합니다. RANGE_NUM이 커질수록 첫 번째 메서드에서 반환되는 목록도 커지고 차지하는 메모리도 커지지만 두 번째 메서드에서는 차이가 없습니다.
무한 횟수로 "반환"할 수 있는 또 다른 예를 살펴보겠습니다.
def fib(): a, b = 1, 1 while True: yield a a, b = b, a+b
이 생성기는 셀 수 없이 많은 "반환 값"을 생성하는 기능이 있으며 사용자는 언제 중지할지 결정할 수 있습니다. 반복
Generator의 고급 응용
사용 시나리오 1:
Generator를 사용하여 다음 작업을 수행할 수 있습니다. 데이터 스트림 생성, 생성기 반환 값을 즉시 생성하지 않고 필요할 때까지 기다립니다. 예를 들어 로그 파일이 있고 각 줄에 대한 레코드가 생성됩니다. 각 기록마다 서로 다른 부서의 사람들이 이를 다르게 처리할 수 있지만 우리는 공통된 주문형 데이터 흐름을 제공할 수 있습니다.
def gen_data_from_file(file_name): for line in file(file_name): yield line def gen_words(line): for word in (w for w in line.split() if w.strip()): yield word def count_words(file_name): word_map = {} for line in gen_data_from_file(file_name): for word in gen_words(line): if word not in word_map: word_map[word] = 0 word_map[word] += 1 return word_map def count_total_chars(file_name): total = 0 for line in gen_data_from_file(file_name): total += len(line) return total if __name__ == '__main__': print count_words('test.txt'), count_total_chars('test.txt')
위의 예는 2008년 PyCon 강의에서 나온 것입니다. gen_words gen_data_from_file
은 데이터 생산자이고 count_words count_total_chars는 데이터 소비자입니다. 보시다시피 데이터는 미리 준비되지 않고 필요할 때만 가져옵니다. 또한 gen_words의 (w for w in line.split() if w.strip())
도 생성기
를 생성합니다. 사용 시나리오 2:
一些编程场景中,一件事情可能需要执行一部分逻辑,然后等待一段时间、或者等待某个异步的结果、或者等待某个状态,然后继续执行另一部分逻辑。比如微服务架构中,服务A执行了一段逻辑之后,去服务B请求一些数据,然后在服务A上继续执行。或者在游戏编程中,一个技能分成分多段,先执行一部分动作(效果),然后等待一段时间,然后再继续。对于这种需要等待、而又不希望阻塞的情况,我们一般使用回调(callback)的方式。下面举一个简单的例子:
def do(a): print 'do', a CallBackMgr.callback(5, lambda a = a: post_do(a)) def post_do(a): print 'post_do', a
这里的CallBackMgr注册了一个5s后的时间,5s之后再调用lambda
函数,可见一段逻辑被分裂到两个函数,而且还需要上下文的传递(如这里的参数a)。我们用yield来修改一下这个例子,yield返回值代表等待的时间。
@yield_dec def do(a): print 'do', a yield 5 print 'post_do', a
这里需要实现一个YieldManager, 通过yield_dec
这个decrator将do这个generator注册到YieldManager,并在5s后调用next方法。Yield版本实现了和回调一样的功能,但是看起来要清晰许多。
下面给出一个简单的实现以供参考:
# -*- coding:utf-8 -*- import sys # import Timer import types import time class YieldManager(object): def __init__(self, tick_delta = 0.01): self.generator_dict = {} # self._tick_timer = Timer.addRepeatTimer(tick_delta, lambda: self.tick()) def tick(self): cur = time.time() for gene, t in self.generator_dict.items(): if cur >= t: self._do_resume_genetator(gene,cur) def _do_resume_genetator(self,gene, cur ): try: self.on_generator_excute(gene, cur) except StopIteration,e: self.remove_generator(gene) except Exception, e: print 'unexcepet error', type(e) self.remove_generator(gene) def add_generator(self, gen, deadline): self.generator_dict[gen] = deadline def remove_generator(self, gene): del self.generator_dict[gene] def on_generator_excute(self, gen, cur_time = None): t = gen.next() cur_time = cur_time or time.time() self.add_generator(gen, t + cur_time) g_yield_mgr = YieldManager() def yield_dec(func): def _inner_func(*args, **kwargs): gen = func(*args, **kwargs) if type(gen) is types.GeneratorType: g_yield_mgr.on_generator_excute(gen) return gen return _inner_func @yield_dec def do(a): print 'do', a yield 2.5 print 'post_do', a yield 3 print 'post_do again', a if __name__ == '__main__': do(1) for i in range(1, 10): print 'simulate a timer, %s seconds passed' % i time.sleep(1) g_yield_mgr.tick()
注意事项:
(1)Yield是不能嵌套的!
def visit(data): for elem in data: if isinstance(elem, tuple) or isinstance(elem, list): visit(elem) # here value retuened is generator else: yield elem if __name__ == '__main__': for e in visit([1, 2, (3, 4), 5]): print e
上面的代码访问嵌套序列里面的每一个元素,我们期望的输出是1 2 3 4 5,而实际输出是1 2 5 。为什么呢,如注释所示,visit是一个generator function
,所以第4行返回的是generator object
,而代码也没这个generator实例迭代。那么改改代码,对这个临时的generator 进行迭代就行了。
def visit(data): for elem in data: if isinstance(elem, tuple) or isinstance(elem, list): for e in visit(elem): yield e else: yield elem
或者在python3.3中 可以使用yield from
,这个语法是在pep380加入的
def visit(data): for elem in data: if isinstance(elem, tuple) or isinstance(elem, list): yield from visit(elem) else: yield elem
(2)generator function中使用return
在python doc中,明确提到是可以使用return的,当generator执行到这里的时候抛出StopIteration异常。
def gen_with_return(range_num): if range_num < 0: return else: for i in xrange(range_num): yield i if __name__ == '__main__': print list(gen_with_return(-1)) print list(gen_with_return(1))
但是,generator function
中的return是不能带任何返回值的
def gen_with_return(range_num): if range_num < 0: return 0 else: for i in xrange(range_num): yield i
上面的代码会报错:SyntaxError: 'return' with argument inside generator
总结
위 내용은 Python의 Yield 및 Generator에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제









C 언어에는 내장 합계 기능이 없으므로 직접 작성해야합니다. 합계는 배열 및 축적 요소를 가로 질러 달성 할 수 있습니다. 루프 버전 : 루프 및 배열 길이를 사용하여 계산됩니다. 포인터 버전 : 포인터를 사용하여 배열 요소를 가리키며 효율적인 합계는 자체 증가 포인터를 통해 달성됩니다. 동적으로 배열 버전을 할당 : 배열을 동적으로 할당하고 메모리를 직접 관리하여 메모리 누출을 방지하기 위해 할당 된 메모리가 해제되도록합니다.

구별되고 구별되는 것은 구별과 관련이 있지만, 다르게 사용됩니다. 뚜렷한 (형용사)는 사물 자체의 독창성을 묘사하고 사물 사이의 차이를 강조하는 데 사용됩니다. 뚜렷한 (동사)는 구별 행동이나 능력을 나타내며 차별 과정을 설명하는 데 사용됩니다. 프로그래밍에서 구별은 종종 중복 제거 작업과 같은 컬렉션에서 요소의 독창성을 나타내는 데 사용됩니다. 홀수 및 짝수 숫자를 구별하는 것과 같은 알고리즘이나 함수의 설계에 별개가 반영됩니다. 최적화 할 때 별도의 작업은 적절한 알고리즘 및 데이터 구조를 선택해야하며, 고유 한 작업은 논리 효율성의 구별을 최적화하고 명확하고 읽을 수있는 코드 작성에주의를 기울여야합니다.

기술 및 산업 요구에 따라 Python 및 JavaScript 개발자에 대한 절대 급여는 없습니다. 1. 파이썬은 데이터 과학 및 기계 학습에서 더 많은 비용을 지불 할 수 있습니다. 2. JavaScript는 프론트 엔드 및 풀 스택 개발에 큰 수요가 있으며 급여도 상당합니다. 3. 영향 요인에는 경험, 지리적 위치, 회사 규모 및 특정 기술이 포함됩니다.

! x 이해! x는 C 언어로 된 논리적 비 운영자입니다. 그것은 x의 값, 즉 실제 변경, 거짓, 잘못된 변경 사항을 부수합니다. 그러나 C의 진실과 거짓은 부울 유형보다는 숫자 값으로 표시되며, 0이 아닌 것은 참으로 간주되며 0만이 거짓으로 간주됩니다. 따라서! x는 음수를 양수와 동일하게 처리하며 사실로 간주됩니다.

합에 대한 C에는 내장 합계 기능이 없지만 다음과 같이 구현할 수 있습니다. 루프를 사용하여 요소를 하나씩 축적합니다. 포인터를 사용하여 요소를 하나씩 액세스하고 축적합니다. 큰 데이터 볼륨의 경우 병렬 계산을 고려하십시오.

코드 취약점, 브라우저 호환성, 성능 최적화, 보안 업데이트 및 사용자 경험 개선과 같은 요소로 인해 H5 페이지를 지속적으로 유지해야합니다. 효과적인 유지 관리 방법에는 완전한 테스트 시스템 설정, 버전 제어 도구 사용, 페이지 성능을 정기적으로 모니터링하고 사용자 피드백 수집 및 유지 관리 계획을 수립하는 것이 포함됩니다.

코드 복사 및 붙여 넣기는 불가능하지는 않지만주의해서 처리해야합니다. 코드의 환경, 라이브러리, 버전 등과 같은 종속성은 현재 프로젝트와 일치하지 않으므로 오류 또는 예측할 수없는 결과를 초래할 수 있습니다. 파일 경로, 종속 라이브러리 및 Python 버전을 포함하여 컨텍스트가 일관되게 유지하십시오. 또한 특정 라이브러리의 코드를 복사 및 붙여 넣을 때 라이브러리 및 해당 종속성을 설치해야 할 수도 있습니다. 일반적인 오류에는 경로 오류, 버전 충돌 및 일관되지 않은 코드 스타일이 포함됩니다. 성능 최적화는 코드의 원래 목적 및 제약에 따라 재 설계 또는 리팩토링되어야합니다. 복사 코드를 이해하고 디버그하고 맹목적으로 복사하여 붙여 넣지 않는 것이 중요합니다.

크롤링하는 동안 58.com 작업 페이지의 동적 데이터를 얻는 방법은 무엇입니까? Crawler 도구를 사용하여 58.com의 작업 페이지를 크롤링 할 때는이 문제가 발생할 수 있습니다.
