Какво прави ключовата дума за доходност?

Каква е ползата от ключовата дума yield в Python? Какво прави?

Например се опитвам да разбера този код 1 :

 def _get_child_candidates(self, distance, min_dist, max_dist): if self._leftchild and distance - max_dist < self._median: yield self._leftchild if self._rightchild and distance + max_dist >= self._median: yield self._rightchild 

А това е наречие

 result, candidates = [], [self] while candidates: node = candidates.pop() distance = node._get_dist(obj) if distance <= max_dist and distance >= min_dist: result.extend(node._values) candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) return result 

Какво се случва, когато методът _get_child_candidates ? Връща ли се списъкът? Един елемент? Пак ли се нарича? Кога ще спрат последващите повиквания?


1. Кодът е взет от Jochen Schulz (jrschulz), който създаде отлична Python библиотека за метрични пространства. Това е линк към пълния източник: Модулът mspace .

8911
дадено от Алекс. 24 окт. S. 24 oct. 2008-10-24 01:21 '08 в 1:21 am 2008-10-24 01:21
@ 46 отговора
  • 1
  • 2

Друг TL; DR

Iterator в списъка : next() връща следващия елемент от списъка

Генераторът на итератори : next() ще изчисли следващия елемент в движение (код за изпълнение)

Можете да видите културата / генератора като начин да стартирате ръчно поток отвън отвън (например, да продължите цикъла една стъпка), като извикате next , без значение колко е трудно.

Забележка : Генераторът НЕ е нормална функция. Тя помни предишното състояние като локални променливи (стек). Вижте други отговори или статии за подробно обяснение. Генераторът може да се повтаря само веднъж . Можеш да направиш без yield , но няма да е толкова добро, така че може да се счита за "много добър" език на захарта.

27
22 июня '16 в 12:40 2016-06-22 12:40 Отговорът е даден от Кристоф Руси на 22 юни'16 в 12:40 часа 2016-06-22 12:40

добивът е подобен на добива. Разликата е, че:

Добивът прави функцията итеративна (в следващия пример функцията primes(n = 1) става повтаряща се).
По същество това означава, че при следващото извикване на функцията, тя ще продължи от мястото, където е излязла (след линията на yield expression на yield expression ).

 def isprime(n): if n == 1: return False for x in range(2, n): if n % x == 0: return False else: return True def primes(n = 1): while(True): if isprime(n): yield n n += 1 for n in primes(): if n > 100: break print(n) 
border=0

В горния пример, ако isprime(n) е вярно, той ще върне просто число. Следващата итерация ще продължи от следващия ред.

 n += 1 
24
29 апр. отговорът е даден на blueray 29 април 2017-04-29 20:22 '17 в 20:22 2017-04-29 20:22

Ключова дума за yield

На пръв поглед, yield използва за дефиниране на генератори, които заменят функциите за return да осигурят резултата на повикващия, без да унищожават локалните променливи. За разлика от функцията, при която при всяко извикване тя започва с нов набор от променливи, генераторът възобновява изпълнението от мястото, където е спряно.

Относно Python генераторите Тъй като ключовата дума yield се използва само с генератори, има смисъл първо да си припомним концепцията за генераторите.

Идеята на генераторите е да изчисляват поредица от резултати по заявка (в движение). В най-простия случай генераторът може да се използва като списък, където всеки елемент се изчислява мързеливо. Да сравним списъка и генератора, които правят едно и също нещо - връщат се степени от две:

 >>> # First, we define a list >>> the_list = [2**x for x in range(5)] >>> >>> # Type check: yes, it a list >>> type(the_list) <class 'list'> >>> >>> # Iterate over items and print them >>> for element in the_list: ... print(element) ... 1 2 4 8 16 >>> >>> # How about the length? >>> len(the_list) 5 >>> >>> # Ok, now a generator. >>> # As easy as list comprehensions, but with '()' instead of '[]': >>> the_generator = (x+x for x in range(3)) >>> >>> # Type check: yes, it a generator >>> type(the_generator) <class 'generator'> >>> >>> # Iterate over items and print them >>> for element in the_generator: ... print(element) ... 0 2 4 >>> >>> # Everything looks the same, but the length... >>> len(the_generator) Traceback (most recent call last): File "", line 1, in TypeError: object of type 'generator' has no len() 

Разглеждайки списъка и генераторът изглежда точно по същия начин. Въпреки това, въпреки че генераторът е итеративен, той не е колекция и следователно няма дължина. Колекции (списъци, кортежи, комплекти и др.) Съхранявайте всички стойности в паметта и можем да ги достъпваме, ако е необходимо. Генераторът изчислява стойностите в движение и ги забравя, така че няма представа за собствения си набор от резултати.

Генераторите са особено полезни за задачи с интензивна памет, когато не е необходимо всички елементи от списъка с големи количества памет да са запазени едновременно. Изчисляването на поредица от стойности един по един също може да бъде полезно в ситуации, в които никога не се изисква пълен резултат, като се дават междинни резултати на повикващия, докато се изпълни някакво изискване и по-нататъшната обработка не се прекрати.

Използване на ключова дума за yield на Python

Добър пример е задачата за търсене, където обикновено не е нужно да чакате, докато се намерят всички резултати. Извършвайки търсене във файловата система, потребителят би бил щастлив да получи резултати в движение и да не чака, докато търсачката провери всеки файл и след това върне резултатите. Има ли хора, които наистина виждат всички резултати от търсенето с Google на последната страница?

Тъй като функцията за търсене не може да бъде създадена с помощта на списъчни изгледи, ще дефинираме генератора, като използваме функцията с оператор за доходност / ключова дума. Декларацията за доходност трябва да бъде поставена на място, където генераторът връща междинен резултат на повикващия и спи до следващото повикване.

 def search(keyword, filename): print('generator started') f = open(filename, 'r') # Looping through the file line by line for line in f: if keyword in line: # If keyword found, return it yield line f.close() 

Досега са описани най-практичните аспекти на генераторите на Python. За повече информация и интересна дискусия погледнете Python Enhancement Предложение 255, в което подробно се разглеждат особеностите на езика.

Щастлив Pythoning! За повече информация посетете http://pythoncentral.io/python-generators-and-yield-keyword/

22
23 марта '16 в 4:18 2016-03-23 04:18 отговорът е даден drewteriyaki 23 март 16 в 4:18 2016-03-23 ​​04:18

Всички отговори тук са големи; но само един от тях (този с най-много гласове) се отнася до начина, по който работи вашият код . Други засягат генераторите като цяло и начина, по който работят.

Следователно няма да повтарям това, което са генераторите или какво прави рентабилността; Мисля, че те са покрити с добри съществуващи отговори. Въпреки това, след като прекарах няколко часа, опитвайки се да разбера код, подобен на твоя, ще го счупя, как работи.

Вашият код пресича двоичната структура на дървото. Да вземем това дърво за пример:

  5 / \ 3 6 / \ \ 1 4 8 

И още една по-опростена реализация на двоичното преливане на дървото за търсене:

 class Node(object): .. def __iter__(self): if self.has_left_child(): for child in self.left: yield child yield self.val if self.has_right_child(): for child in self.right: yield child 

Кодът за изпълнение е в обект Tree който реализира __iter__ така:

 def __iter__(self): class EmptyIter(): def next(self): raise StopIteration if self.root: return self.root.__iter__() return EmptyIter() 

Изявлението while candidates може да бъде заменено for element in tree ; Python превежда това на

 it = iter(TreeObj) # returns iter(self.root) which calls self.root.__iter__() for element in it: .. process element .. 

Тъй като функцията Node.__iter__ е генератор, кодът вътре в него се изпълнява в една итерация. Така изпълнението ще изглежда така:

  1. коренният елемент е първият; проверете дали е напуснал децата и for повторения (нека се нарича it1, защото това е първият обект на iterator)
  2. тя има дете, затова се екзекутира. Обектът for child in self.left създава нов итератор от self.left , който сам по себе си е Node обект (it2)
  3. Същата логика като за 2 и се създава нов iterator (it3)
  4. Сега стигнахме до левия край на дървото. it3 няма останали потомци, така че продължава да yield self.value
  5. Следващия път, когато се обадите на next(it3) той извиква StopIteration и съществува, защото няма правилни деца (достига края на функцията, връща нищо)
  6. it1 и it2 са все още активни - те не са изчерпани, а повикването next(it2) ще даде стойности, а не причинява StopIteration
  7. Сега се връщаме към контекста it2 и извикваме next(it2) който продължава там, където е спрял: веднага след yield child за yield child . Тъй като той вече не е напуснал потомците си, той продължава да се self.val .

Номерът тук е, че всяка итерация създава суб-тетратори за преминаване през дървото и съдържа състоянието на текущия итератор. Щом достигне края, той пресича стака и стойностите се връщат в правилния ред (първо най-ниската стойност на доходност).

Вашият примерен код е направил нещо подобно в друга техника: той попълва списък с един елемент за всеки елемент на дете, след това при следващата итерация се появява и изпълнява кода на функцията за текущия обект (следователно self ).

Надявам се това да е допринесло малко за тази легендарна тема. Прекарах няколко часа в опит да разбера този процес.

10
03 окт. отговор, даден от Чен А. 3 октомври 2017-10-03 14:30 '17 в 14:30 часа 2017-10-03 14:30

Накратко, използването на доходността е подобно на ключовата дума return , с изключение на това, че тя връща генератор .
Обектът на генератора преминава само веднъж .

Изходът има две предимства:

  1. Не е необходимо да четете тези стойности два пъти;
  2. Можете да получите много възли за деца, без да ги поставяте в паметта.
8
04 апр. Отговорът е даден 123 04 Април. 2017-04-04 05:23 '17 в 05:23 часа 2017-04-04 05:23

В Python, generators (специален тип iterators ) се използват за генериране на серия от стойности, а ключовата дума yield е подобна на ключовата дума за return на функциите на генератора.

Друга интересна ключова дума за yield е поддържането на функцията за генератор на state .

По този начин, ние можем да зададем number на различна стойност при всяко подаване на generator .

Ето един пример:

 def getPrimes(number): while True: if isPrime(number): number = yield number # a miracle occurs here number += 1 def printSuccessivePrimes(iterations, base=10): primeGenerator = getPrimes(base) primeGenerator.send(None) for power in range(iterations): print(primeGenerator.send(base ** power)) 
6
09 сент. отговорът е даден ARGeo 09 sep . 2018-09-09 16:25 '18 в 16:25 2018-09-09 16:25

предавам

 >>> def create_generator(): ... my_list = range(3) ... for i in my_list: ... yield i*i ... >>> my_generator = create_generator() # create a generator >>> print(my_generator) # my_generator is an object! <generator object create_generator at 0xb7555c34> >>> for i in my_generator: ... print(i) 0 1 4 

Накратко , можете да видите, че цикълът не спира и продължава да функционира дори след изпращането на обект или променлива (за разлика от return когато цикълът спира след изпълнение).

5
17 янв. Гавриел Коен публикува на 17 януари 2018-01-17 15:26 '18 в 15:26 2018-01-17 15:26

Когато извикате функция, тя получава лично пространство от имена, в което се създават неговите локални променливи. Когато функцията достигне оператора return, локалните променливи се унищожават и стойността се връща на повикващия. Последващо повикване към същата функция създава ново лично пространство от имена и нов набор от локални променливи. Но какво, ако местните променливи не бяха изхвърлени от функцията? Какво ще стане, ако по-късно можете да възобновите функцията откъдето е спряло? Това осигуряват генераторите; те могат да се разглеждат като възобновяеми функции.

например:

 def _count(N): for i in range(N): yield i 

Всяка функция, съдържаща ключовата дума yield, е генераторна функция; това се открива от компилатора на байтовия код на Pythons, който в резултат компилира функцията.

Когато извикате функция на генератор, тя не връща единична стойност; вместо това, той връща обект-генератор, който поддържа протокола за итератор. Когато се изпълни декларацията за доходност, генераторът показва стойността на i, подобно на декларацията за връщане. Голямата разлика между производителността и декларацията за връщане е, че когато се достигне изхода, състоянието на изпълнение на генератора се прекъсва и локалните променливи се запазват. Следващият път, когато се извика методът Generator.next (), функцията ще възобнови изпълнението.

 gen = _count(3) print gen.next() print gen.next() print gen.next() #outpot: #0 #1 #2 
2
14 дек. отговорът се дава от a.patidar 14 dec. 2018-12-14 06:17 '18 в 18:17 ч. 2018-12-14 06:17

yield Вид генератор, който може да се използва в Python.

Ето връзката, за да видите какво наистина прави доходността, също и в поколението. Генератори на ключови думи и доход - Python Central (PC)

Също така, yield работи като return , но не като return . Дори има връзка, която обяснява yield , ако не разбирате другата добре. Подобрете умението си за рентабилност - jeffknupp

2
03 дек. Отговорът е даден PIZZZZZZZZZZZA е тук 03 Дек. 2018-12-03 22:18 '18 в 22:18 ч. 2018-12-03 22:18

Започвайки с python3.3, печалбата се поддържа в списъка .

синтаксис:

 In [145]: [(yield i) for i in range(10)] Out[145]: <generator object <listcomp> at 0x107d93e10> 

Ще забележите, че разбирането на списъка с възвращаемостта на генератора на yield . Ще трябва да я конвертирате изрично в списък:

 In [149]: list([(yield i) for i in range(10)]) Out[149]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Забележете, че yield i необходими скоби (...) около yield i , в противен случай възниква SyntaxError :

 In [146]: [yield i for i in range(10)] File "<ipython-input-146-6e991b619b21>", line 1 [yield i for i in range(10)] ^ SyntaxError: invalid syntax 

(Пример 1) Връщащи се квадрати

 In [150]: for sq in [(yield i * i) for i in range(5)]: ...: print(sq) ...: 0 1 4 9 16 

(Пример 2) Добавяне на префикси и суфикси

Можете също да използвате yield from израза, който работи подобно на yield from делегирането на генератора:

 In [153]: x = ['foo', 'bar'] In [154]: for i in [(yield from('_' + y, y, y + '_')) for y in x]: ...: print(i) ...: _foo foo foo_ _bar bar bar_ 

Допълнителни връзки:

  1. използване на рентабилността с разбиране

  2. РЕР-342

1
19 дек. отговорът е даден cᴘᴇᴇᴅs dek 19 dec. 2018-12-19 16:03 '18 в 16:03 ч. 2018-12-19 16:03

Казано по-просто, "доходността" е подобна на стойността на "връщане", но работи в генератора.

1
02 авг. отговорът е даден user3701435 02 авг. 2018-08-02 19:16 '18 в 19:16 2018-08-02 19:16

Декларацията за доходност се използва за дефиниране на генератори, заменяйки функцията return, за да предостави резултата на повикващия, без да унищожава локалните променливи. За разлика от функцията, при която при всяко извикване тя започва с нов набор от променливи, генераторът възобновява изпълнението от мястото, където е спряно.

0
13 апр. отговор, даден abssab 13 април 2018-04-13 12:40 '18 в 12:40 ч. 2018-04-13 12:40

При просто извличане се връща обект-генератор вместо стойности.

По-долу е прост пример за помощ!

 def sim_generator(): for i in range(3): yield(i) obj = sim_generator() next(obj) # another way is obj.__next__() next(obj) next(obj) 

горният код връща 0, 1, 2

или дори кратко

 for val in sim_generator(): print(val) 

връщане 0, 1, 2

Надявам се това да помогне

0
06 февр. отговорът е даден от Vivek Ananthan 06 февруари. 2019-02-06 06:57 '19 в 6:57 2019-02-06 06:57

Трябва да използваме доходността, когато искаме да повторим последователността, но не искаме да запазим цялата последователност в паметта. Добивът се използва в генераторите на Python. Функцията на генератора се дефинира като нормална функция, но когато се налага да генерира стойност, тя прави това, използвайки ключовата дума yield, а не връщане.

0
13 окт. Отговор, даден от Дерек Лейман на 13 октомври 2018-10-13 00:36 '18 в 0:36 2018-10-13 00:36

Представете си печалба като декларация за връщане във функция, но основната разлика е, че декларацията за доходност декларира генератор, докато операторът return дава функция.

-1
19 дек. отговорът е даден MLhacker 19 dec. 2018-12-19 16:04 '18 в 16:04 ч. 2018-12-19 16:04

Проста генераторна функция

 def my_gen(): n = 1 print('This is printed first') # Generator function contains yield statements yield n n += 1 print('This is printed second') yield n n += 1 print('This is printed at last') yield n 

Извлечението за производителност спира функцията, запазва всичките й състояния и след това продължава последователните повиквания.

https://www.programiz.com/python-programming/generator

-1
17 авг. отговор, даден от Сава Махешвари 17 август. 2018-08-17 15:36 '18 в 15:36 ч. 2018-08-17 15:36
  • 1
  • 2

Други въпроси относно таговете, които или Ask a Question