“අස්වැන්න” මූල පදය කරන්නේ කුමක්ද?


10202

yieldපයිතන් හි යතුරු පදයේ භාවිතය කුමක්ද, එය කරන්නේ කුමක්ද?

උදාහරණයක් ලෙස, මම මෙම කේතය 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. මෙම කේත කොටස ලියා ඇත්තේ ජොචෙන් ෂුල්ස් (ජර්ෂල්ස්) විසිනි, ඔහු මෙට්‍රික් අවකාශයන් සඳහා විශිෂ්ට පයිතන් පුස්තකාලයක් සාදන ලදී. සම්පූර්ණ ප්‍රභවයට සබැඳිය මෙයයි: මොඩියුලය mspace .

Answers:


14660

කුමක් yieldකරන්නේ දැයි තේරුම් ගැනීමට, ජනක යන්ත්‍ර යනු කුමක්දැයි ඔබ තේරුම් ගත යුතුය . ඔබ ජනක තේරුම් ගත හැක පෙර, ඔබ තේරුම් ගත යුතු iterables .

අනුකම්පා

ඔබ ලැයිස්තුවක් සාදන විට, ඔබට එහි අයිතම එකින් එක කියවිය හැකිය. එහි අයිතම එකින් එක කියවීම පුනරාවර්තනය ලෙස හැඳින්වේ:

>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3

mylistනැවත කළ හැකි ය . ඔබ ලැයිස්තු අවබෝධය භාවිතා කරන විට, ඔබ ලැයිස්තුවක් සාදයි, එබැවින් එය කළ හැකි ය:

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4

ඔබට " for... in..." මත භාවිතා කළ හැකි සෑම දෙයක්ම නැවත කළ හැකි ය; lists,, stringsගොනු ...

ඔබට අවශ්‍ය පරිදි ඒවා කියවිය හැකි නිසා මෙම පුනරාවර්තන පහසුය, නමුත් ඔබ සියලු අගයන් මතකයේ ගබඩා කර තබන අතර ඔබට බොහෝ අගයන් ඇති විට මෙය සැමවිටම ඔබට අවශ්‍ය නොවේ.

ජනක යන්ත්‍ර

උත්පාදක යන්ත්ර යනු පුනරාවර්තක වේ, ඔබට නැවත නැවත කළ හැක්කේ එක් වරක් පමණි . උත්පාදක යන්ත්රය සියලු අගයන් මතකයේ ගබඩා නොකරයි, ඒවා මැස්සන් මත අගයන් ජනනය කරයි :

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4

ඔබ ()ඒ වෙනුවට භාවිතා කළ ඒවා හැර එය සමාන වේ []. ඒත්, ඔබ කළ නොහැකි ඉටු for i in mygeneratorඔවුන් 0 ගණනය, එය හා ගණනය 1 ගැන අමතක හා ගණනය 4, එකින් එක, අවසන්: ජනක යන්ත්ර එක් වරක් පමණක් භාවිතා කළ හැකි නිසා දෙවැනි වතාවට.

යටත් වෙනවා

yieldවැනි භාවිතා කරන මූල පදය වේ returnඋත්සවයට එක් ජනන යන්ත්රයක ආපසු හැර,.

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

මෙන්න එය නිෂ් less ල උදාහරණයකි, නමුත් ඔබේ ක්‍රියාකාරිත්වය ඔබට එක් වරක් පමණක් කියවිය යුතු වටිනාකම් සමූහයක් ලබා දෙන බව ඔබ දන්නා විට එය පහසුය.

ප්‍රගුණ කිරීම සඳහා yield, ඔබ ශ්‍රිතය අමතන විට, ශ්‍රිතයේ ඔබ ලියා ඇති කේතය ක්‍රියාත්මක නොවන බව ඔබ තේරුම් ගත යුතුය . ශ්‍රිතය මඟින් ජනක වස්තුව පමණක් ලබා දෙයි, මෙය ටිකක් උපක්‍රමශීලී ය :-)

එවිට, ඔබේ කේතය forඋත්පාදක යන්ත්රය භාවිතා කරන සෑම අවස්ථාවකම එය නතර කළ ස්ථානයේ සිට ඉදිරියට යනු ඇත .

දැන් අමාරු කොටස:

forඔබේ ශ්‍රිතයෙන් සාදන ලද උත්පාදක වස්තුව පළමු වරට ඇමතූ විට, එය ආරම්භයේ සිට එය ක්‍රියාත්මක වන තෙක් ඔබේ ශ්‍රිතයේ කේතය ක්‍රියාත්මක කරනු ඇත yield, එවිට එය ලූපයේ පළමු අගය නැවත ලබා දෙනු ඇත. ඉන්පසුව, සෑම ඇමතුමක්ම ඔබ ශ්‍රිතයේ ලියා ඇති ලූපයේ තවත් ක්‍රියාකාරීත්වයක් ක්‍රියාත්මක කර ඊළඟ අගය ලබා දෙනු ඇත. උත්පාදක යන්ත්රය හිස් යැයි සලකන තෙක් මෙය දිගටම පවතිනු ඇත yield. එය විය හැක්කේ ලූපය අවසානයකට පැමිණ ඇති නිසා හෝ ඔබ තවදුරටත් තෘප්තිමත් නොවන නිසා විය හැකිය "if/else".


ඔබේ කේතය පැහැදිලි කර ඇත

උත්පාදක යන්ත්රය:

# Here you create the method of the node object that will return the generator
def _get_child_candidates(self, distance, min_dist, max_dist):

    # Here is the code that will be called each time you use the generator object:

    # If there is still a child of the node object on its left
    # AND if the distance is ok, return the next child
    if self._leftchild and distance - max_dist < self._median:
        yield self._leftchild

    # If there is still a child of the node object on its right
    # AND if the distance is ok, return the next child
    if self._rightchild and distance + max_dist >= self._median:
        yield self._rightchild

    # If the function arrives here, the generator will be considered empty
    # there is no more than two values: the left and the right children

අමතන්නා:

# Create an empty list and a list with the current object reference
result, candidates = list(), [self]

# Loop on candidates (they contain only one element at the beginning)
while candidates:

    # Get the last candidate and remove it from the list
    node = candidates.pop()

    # Get the distance between obj and the candidate
    distance = node._get_dist(obj)

    # If distance is ok, then you can fill the result
    if distance <= max_dist and distance >= min_dist:
        result.extend(node._values)

    # Add the children of the candidate in the candidate's list
    # so the loop will keep running until it will have looked
    # at all the children of the children of the children, etc. of the candidate
    candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))

return result

මෙම කේතයේ ස්මාර්ට් කොටස් කිහිපයක් අඩංගු වේ:

  • ලූපය නැවත ලැයිස්තුවක් මත පුනරාවර්තනය වේ, නමුත් ලූපය නැවත ක්‍රියාත්මක වන විට ලැයිස්තුව පුළුල් වේ :-) එය අනන්ත පුඩුවක් සමඟ අවසන් විය හැකි බැවින් එය තරමක් භයානක වුවත් මෙම සියලු කැදැලි දත්ත හරහා ගමන් කිරීම සංක්ෂිප්ත ක්‍රමයකි. මෙම අවස්ථාවෙහිදී, candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))උත්පාදක යන්ත්රයේ සියලු අගයන් පිට කරන්න, නමුත් එකම උත්පාදක යන්ත්රය whileඑකම නෝඩයක් මත යොදන බැවින් පෙර ඒවාට වඩා වෙනස් අගයන් නිපදවන නව උත්පාදක වස්තු නිර්මාණය කරමින් සිටී.

  • මෙම extend()ක්‍රමය ලැයිස්තු වස්තු ක්‍රමයක් වන අතර එය නැවත සැකසිය හැකි දෙයක් අපේක්ෂා කරන අතර එහි අගයන් ලැයිස්තුවට එක් කරයි.

සාමාන්‍යයෙන් අපි එයට ලැයිස්තුවක් යමු:

>>> a = [1, 2]
>>> b = [3, 4]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4]

නමුත් ඔබේ කේතය තුළ එයට ජනක යන්ත්‍රයක් ලැබේ, එය හොඳ නිසා:

  1. ඔබට අගයන් දෙවරක් කියවීමට අවශ්‍ය නැත.
  2. ඔබට දරුවන් විශාල ප්‍රමාණයක් සිටිය හැකි අතර ඔවුන් සියල්ලන්ම මතකයේ ගබඩා කර තැබීමට ඔබට අවශ්‍ය නැත.

එය ක්‍රියාත්මක වන්නේ ක්‍රමයක තර්කය ලැයිස්තුවක් ද නැද්ද යන්න පයිතන් ගණන් නොගන්නා බැවිනි. පයිතන් පුනරාවර්තන බලාපොරොත්තු වන අතර එමඟින් එය නූල්, ලැයිස්තු, ටුපල් සහ ජනක යන්ත්‍ර සමඟ ක්‍රියා කරනු ඇත! මෙය තාරා ටයිප් කිරීම ලෙස හැඳින්වෙන අතර පයිතන් මෙතරම් සිසිල් වීමට එක් හේතුවකි. නමුත් මෙය තවත් කතාවකි, තවත් ප්‍රශ්නයකට ...

ඔබට මෙහි නැවැත්විය හැකිය, නැතහොත් උත්පාදක යන්ත්රයේ උසස් භාවිතයක් බැලීමට ටිකක් කියවන්න:

උත්පාදක වෙහෙස පාලනය කිරීම

>>> class Bank(): # Let's create a bank, building ATMs
...    crisis = False
...    def create_atm(self):
...        while not self.crisis:
...            yield "$100"
>>> hsbc = Bank() # When everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # Crisis is coming, no more money!
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
>>> for cash in brand_new_atm:
...    print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...

සටහන: පයිතන් 3 සඳහා, භාවිතා කරන්න print(corner_street_atm.__next__())හෝprint(next(corner_street_atm))

සම්පතකට ප්‍රවේශය පාලනය කිරීම වැනි විවිධ දේ සඳහා එය ප්‍රයෝජනවත් වේ.

ඉටර්ටූල්ස්, ඔබේ හොඳම මිතුරා

Itertools මොඩියුලය මඟින් iterable හැසිරවීමට විශේෂ කාර්යයන් අඩංගු වේ. උත්පාදක යන්ත්රයක් අනුපිටපත් කිරීමට කවදා හෝ කැමතිද? ජනක යන්ත්‍ර දෙකක් දම්වැල් ද? එක් ලයිනර් සහිත කූඩු ලැයිස්තුවක කණ්ඩායම් අගයන්? Map / Zipවෙනත් ලැයිස්තුවක් නිර්මාණය නොකර?

එහෙනම් import itertools.

උදාහරණයක්? අශ්වයන් හතරක තරඟයක් සඳහා පැමිණිය හැකි ඇණවුම් බලමු:

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
 (1, 2, 4, 3),
 (1, 3, 2, 4),
 (1, 3, 4, 2),
 (1, 4, 2, 3),
 (1, 4, 3, 2),
 (2, 1, 3, 4),
 (2, 1, 4, 3),
 (2, 3, 1, 4),
 (2, 3, 4, 1),
 (2, 4, 1, 3),
 (2, 4, 3, 1),
 (3, 1, 2, 4),
 (3, 1, 4, 2),
 (3, 2, 1, 4),
 (3, 2, 4, 1),
 (3, 4, 1, 2),
 (3, 4, 2, 1),
 (4, 1, 2, 3),
 (4, 1, 3, 2),
 (4, 2, 1, 3),
 (4, 2, 3, 1),
 (4, 3, 1, 2),
 (4, 3, 2, 1)]

පුනරාවර්තනයේ අභ්‍යන්තර යාන්ත්‍රණයන් අවබෝධ කර ගැනීම

අනුකරණය කිරීම යනු පුනරාවර්තන ( __iter__()ක්‍රමවේදය ක්‍රියාත්මක කිරීම ) සහ අනුකාරක ( __next__()ක්‍රමවේදය ක්‍රියාත්මක කිරීම ) යන ක්‍රියාවලියකි. අනුකාරක යනු ඔබට අනුකාරකයක් ලබා ගත හැකි ඕනෑම වස්තුවකි. අනුකාරක යනු ඔබට නැවත සැකසීමට ඉඩ දෙන වස්තු වේ.

ලූප ක්‍රියා කරන ආකාරයfor ගැන මේ ලිපියේ වැඩි විස්තර ඇත .


355
yieldමෙම පිළිතුරෙන් ඇඟවෙන්නේ ඉන්ද්‍රජාලික නොවේ. ඔබ yieldඕනෑම තැනක ප්‍රකාශයක් අඩංගු ශ්‍රිතයක් අමතන විට , ඔබට උත්පාදක වස්තුවක් ලැබෙනු ඇත, නමුත් කේතයක් ක්‍රියාත්මක නොවේ. ඔබ උත්පාදක යන්ත්රයෙන් වස්තුවක් උකහා ගන්නා සෑම අවස්ථාවකම, පයිතන් yieldප්රකාශයක් පැමිණෙන තෙක් ශ්‍රිතය තුළ කේතය ක්‍රියාත්මක කරයි , පසුව එය විරාමයක් ලබා දෙයි. ඔබ වෙනත් වස්තුවක් නිස්සාරණය කරන විට, පයිතන් නැවත ආරම්භ වී yieldඑය තවත් එකක් කරා ළඟා වන තෙක් ඉදිරියට යයි yield(බොහෝ විට එකම එකකි, නමුත් පසුව එක් පුනරාවර්තනයක්). ශ්‍රිතය අවසානයෙන් ඉවතට යන තෙක් මෙය දිගටම පවතින අතර එම අවස්ථාවේදී උත්පාදක යන්ත්රය අවසන් වී ඇති බව සලකනු ලැබේ.
මතියස් ෆ්‍රිප්

30
"මෙම පුනරාවර්තන පහසුය ... නමුත් ඔබ සියලු අගයන් මතකයේ ගබඩා කර තබයි. මෙය සැමවිටම ඔබට අවශ්‍ය දේ නොවේ", වැරදි හෝ ව්‍යාකූල වේ. පුනරාවර්තකය මඟින් iter () නැවත ඇමතීමෙන් ආපසු ලබා දෙන අතර, iterator සෑම විටම එහි අගයන් මතකයේ ගබඩා කර තැබිය යුතු නැත, iter ක්‍රමය ක්‍රියාත්මක කිරීම මත පදනම්ව, ඉල්ලුමට අනුව අනුපිළිවෙලින් අගයන් උත්පාදනය කළ හැකිය.
පික්මේට් 涅

මෙම ශ්‍රේෂ් answer පිළිතුරට එකතු කිරීම සතුටක් වනුයේ ඔබ ()ඒ වෙනුවට භාවිතා කළ දේ හැර[] , විශේෂයෙන් කුමක් ද ()යන්න (ටුපල් සමඟ ව්‍යාකූලත්වයක් තිබිය හැකිය).
WoJ

මම වැරදියි, නමුත් උත්පාදක යන්ත්රය අනුකාරකයක් නොවේ, "උත්පාදක යන්ත්රය" යනු අනුකාරකයකි.
aderchox

AtMatthiasFripp "ශ්‍රිතය අවසානය දක්වා ක්‍රියාත්මක වන තෙක් මෙය දිගටම පවතී" - නැතහොත් එය returnප්‍රකාශයක් හමු වේ . ( ප්‍රතිලාභ අගයක් නියම කර නොමැති නම්, returnඅඩංගු ශ්‍රිතයක් සඳහා අවසර දෙනු ලැබේ yield.)
alaniwi

2007

තේරුම් ගැනීමට කෙටිමඟ yield

yieldප්‍රකාශයන් සහිත ශ්‍රිතයක් ඔබ දුටු විට , සිදුවන්නේ කුමක්ද යන්න තේරුම් ගැනීමට මෙම පහසු උපක්‍රමය යොදන්න:

  1. result = []ශ්‍රිතයේ ආරම්භයේ දී රේඛාවක් ඇතුළු කරන්න .
  2. එක් එක් වෙනුවට yield exprසමග result.append(expr).
  3. return resultශ්‍රිතයේ පතුලේ රේඛාවක් ඇතුළු කරන්න .
  4. ඔව් - තවත් yieldප්‍රකාශ නැත ! කේතය කියවා හඳුනා ගන්න.
  5. ශ්‍රිතය මුල් අර්ථ දැක්වීම සමඟ සසඳන්න.

මෙම උපක්‍රමය මඟින් ශ්‍රිතය පිටුපස ඇති තර්කනය පිළිබඳ අදහසක් ලබා දෙනු ඇත, නමුත් ඇත්ත වශයෙන්ම සිදුවන්නේ yieldකුමක්ද යන්න ලැයිස්තු පදනම් කරගත් ප්‍රවේශයට වඩා සැලකිය යුතු ලෙස වෙනස් වේ. බොහෝ අවස්ථාවන්හීදී, අස්වැන්න ප්‍රවේශය වැඩි මතක ශක්තියක් සහ වේගවත් වනු ඇත. වෙනත් අවස්ථාවල දී, මුල් උපක්‍රමය හොඳින් ක්‍රියාත්මක වුවද, මෙම උපක්‍රමය මඟින් ඔබ අසීමිත පුඩුවක් තුළ සිර වනු ඇත. වැඩිදුර ඉගෙනීමට කියවන්න ...

ඔබේ අයිටරබල්ස්, ඉටරේටර්ස් සහ ජනක යන්ත්‍ර පටලවා නොගන්න

පළමුව, iterator ප්‍රොටෝකෝලය - ඔබ ලියන විට

for x in mylist:
    ...loop body...

පයිතන් පහත පියවර දෙක සිදු කරයි:

  1. මේ සඳහා අනුකාරකයක් ලැබේ mylist:

    අමතන්න iter(mylist)-> මෙය next()ක්‍රමයක් සහිත වස්තුවක් ලබා දෙයි (හෝ __next__()පයිතන් 3 හි).

    [බොහෝ දෙනා ඔබට පැවසීමට අමතක කරන පියවර මෙයයි]

  2. අයිතම හරහා ලූප් කිරීමට iterator භාවිතා කරයි:

    ඇමතුම් තබා next()සිට පියවර 1. සිට ආපසු ලැබෙන අගය ආපසු iterator මත ක්රමය next()අනුයුක්ත කර ඇත xහා ලූප ශරීරය ක්රියාත්මක වේ. ව්‍යතිරේකයක් StopIterationඅභ්‍යන්තරයෙන් මතු කරන්නේ නම් next(), එයින් අදහස් කරන්නේ අනුකාරකයේ තවත් අගයන් නොමැති අතර ලූපය පිටවන බවයි.

සත්යය නම් පයිතන් වස්තුවක අන්තර්ගතය ඉක්මවා යාමට අවශ්‍ය ඕනෑම වේලාවක ඉහත පියවර දෙක ඉටු කරයි - එබැවින් එය ලූපයක් විය හැකි නමුත් එය කේතයක් විය හැකිය otherlist.extend(mylist)( otherlistපයිතන් ලැයිස්තුවක් ඇති තැන).

මෙන්න iterator ප්‍රොටෝකෝලය ක්‍රියාත්මක කරන නිසා එය mylistනැවත කළ හැකි ය . පරිශීලක-නිර්වචනය කරන ලද පන්තියක දී, __iter__()ඔබේ පන්තියේ අවස්ථා නැවත සැකසිය හැකි ක්‍රමයක් ක්‍රියාත්මක කළ හැකිය . මෙම ක්‍රමය මඟින් අනුකාරකයක් නැවත ලබා දිය යුතුය . Iterator යනු ක්‍රමයක් සහිත වස්තුවකි next(). ඒ දෙකම ක්රියාත්මක කිරීමට හැකියාව __iter__()හා next()එම පන්තිය මත ඇති, සහ __iter__()නැවත self. මෙය සරල අවස්ථා සඳහා ක්‍රියා කරනු ඇත, නමුත් ඔබට එකම වස්තුවක් මත එකවර පුනරාවර්තන දෙකක් ලූප අවශ්‍ය විට නොවේ.

ඉතින් එය අනුකාරක ප්‍රොටෝකෝලයයි, බොහෝ වස්තූන් මෙම ප්‍රොටෝකෝලය ක්‍රියාත්මක කරයි:

  1. සාදන ලද ලැයිස්තු, ශබ්ද කෝෂ, ටුපල්, කට්ටල, ලිපිගොනු.
  2. ක්‍රියාත්මක කරන පරිශීලක අර්ථ දක්වන පන්ති __iter__().
  3. ජනක යන්ත්‍ර.

forලූපයක් එය සමඟ කටයුතු කරන්නේ කුමන ආකාරයේ වස්තුවක් දැයි නොදන්නා බව සලකන්න - එය හුදෙක් අනුකාරක ප්‍රොටෝකෝලය අනුගමනය කරන අතර අයිතමය ඇමතීමේදී අයිතමය ලබා ගැනීමට සතුටු වේ next(). බිල්ට් ලැයිස්තු ඔවුන්ගේ අයිතම එකින් එක ආපසු යවයි, ශබ්ද කෝෂ යතුරු එකින් එක යවයි, ලිපිගොනු එකින් එක රේඛා යවයි . සහ ජනක යන්ත්‍ර නැවත පැමිණේ ... හොඳයි එතැනට yieldඑන්නේ:

def f123():
    yield 1
    yield 2
    yield 3

for item in f123():
    print item

yieldප්‍රකාශ වෙනුවට , ඔබට ප්‍රකාශ තුනක් returnතිබේ f123()නම් පළමුවැන්න පමණක් ක්‍රියාත්මක වන අතර ශ්‍රිතය පිටව යනු ඇත. නමුත් f123()සාමාන්‍ය කාර්යයක් නොවේ. f123()කැඳවූ විට , එය අස්වැන්න ප්‍රකාශවල කිසිදු අගයක් ලබා නොදේ ! එය උත්පාදක වස්තුවක් ආපසු ලබා දෙයි. එසේම, ශ්‍රිතය සැබවින්ම පිටවන්නේ නැත - එය අත්හිටවූ තත්වයකට යයි. forඋත්පාදක වස්තුවට වඩා ලූපය ලූපයක් වීමට උත්සාහ කරන විට , ශ්‍රිතය කලින් අත්හිටවූ පසු එහි අත්හිටවූ තත්වයෙන් yieldනැවත ආරම්භ වේ, ඊළඟ කේත පේළිය ක්‍රියාත්මක කරයි, මේ අවස්ථාවේ දී yieldප්‍රකාශයක් ලබා දී එය ඊළඟට යවයි අයිතමය. මෙය සිදු වන්නේ ශ්‍රිතය පිටවන තුරු වන අතර, එම අවස්ථාවේදී උත්පාදක යන්ත්රය මතු StopIterationවන අතර ලූපය පිටවෙයි.

විදුලි උත්පාදක වස්තුව එසේ කරන්නේ ඇඩප්ටරය වැනි වර්ගයේ - එක් අවසානයේ දී එය හෙලිදරව් කිරීම මඟින්, මෙම iterator ප්රොටෝකෝලය ප්රදර්ශනය __iter__()හා next()පවත්වා ගැනීමට ක්රම forපුඩුවක් සතුටු. කෙසේ වෙතත්, අනෙක් අන්තයේ, එය ඊළඟ අගය එයින් ලබා ගැනීමට ප්‍රමාණවත් තරම් ශ්‍රිතය ක්‍රියාත්මක කර නැවත අත්හිටවූ ප්‍රකාරයට දමයි.

ජනක යන්ත්‍ර භාවිතා කරන්නේ ඇයි?

සාමාන්‍යයෙන්, ඔබට ජනක යන්ත්‍ර භාවිතා නොකරන නමුත් එකම තර්කනය ක්‍රියාත්මක කරන කේත ලිවිය හැකිය. එක් විකල්පයක් නම් මා කලින් සඳහන් කළ තාවකාලික ලැයිස්තුව 'උපක්‍රමය' භාවිතා කිරීමයි. එය සෑම අවස්ථාවකම ක්‍රියා නොකරනු ඇත, උදා: ඔබට අසීමිත ලූප තිබේ නම්, හෝ ඔබට දිගු ලැයිස්තුවක් ඇති විට එය මතකය අකාර්යක්ෂම ලෙස භාවිතා කරයි. අනෙක් ප්‍රවේශය නම් නව ක්‍රියාකාරී පංතියක් වන සමින්ටිං ඉටර් ක්‍රියාත්මක කිරීම ය. එය රාජ්‍යය උදාහරණ සාමාජිකයන් ලෙස තබාගෙන එහි next()(හෝ __next__()පයිතන් 3) ක්‍රමයේ ඊළඟ තාර්කික පියවර සිදු කරයි . තර්කනය මත පදනම්ව, next()ක්‍රමවේදය තුළ ඇති කේතය ඉතා සංකීර්ණ පෙනුමක් ඇති අතර දෝෂ වලට ගොදුරු විය හැකිය. මෙහිදී ජනක යන්ත්‍ර පිරිසිදු හා පහසු විසඳුමක් සපයයි.


20
"අස්වැන්න ප්‍රකාශයන් සහිත ශ්‍රිතයක් ඔබ දුටු විට, කුමක් සිදුවේද යන්න තේරුම් ගැනීමට මෙම පහසු උපක්‍රමය යොදන්න" මෙය ඔබට sendජනක යන්ත්‍රයකට ඇතුළු විය හැකි බව මුළුමනින්ම නොසලකා හරිනවාද? එය උත්පාදක ලක්ෂ්‍යයේ විශාල කොටසකි.
ඩැනියෙල්සෑන්ක්

10
"එය ලූප සඳහා විය හැකිය, නමුත් එය වැනි කේතයක් විය හැකිය otherlist.extend(mylist)" -> මෙය වැරදිය. extend()තැනින් තැන ලැයිස්තුව වෙනස් කරන අතර එය නැවත ලබා ගත නොහැක. ව්‍යංගයෙන් නැවත පැමිණෙන නිසා ඔබට නැවත ලූප් කිරීමට උත්සාහ කිරීම otherlist.extend(mylist)අසාර්ථක වනු ඇත . TypeErrorextend()NoneNone
පේද්‍රෝ

4
@pedro ඔබ එම වාක්‍යය වරදවා වටහාගෙන ඇත. එය පිඹුරා කිරිමටද මත සඳහන් පියවර දෙකක් අදහස් mylist(මත නොව otherlistක්රියාත්මක විට) otherlist.extend(mylist).
අද

555

මේ ගැන සිතන්න:

Iterator යනු next()ක්‍රමයක් ඇති වස්තුවක් සඳහා මනස්කාන්ත ශබ්දයක් පමණි . එබැවින් අස්වැන්නක් සහිත ශ්‍රිතයක් මේ වගේ දෙයක් බවට පත්වේ:

මුල් අනුවාදය:

def some_function():
    for i in xrange(4):
        yield i

for i in some_function():
    print i

ඉහත කේතය සමඟ පයිතන් පරිවර්තකයා කරන්නේ මෙයයි:

class it:
    def __init__(self):
        # Start at -1 so that we get 0 when we add 1 below.
        self.count = -1

    # The __iter__ method will be called once by the 'for' loop.
    # The rest of the magic happens on the object returned by this method.
    # In this case it is the object itself.
    def __iter__(self):
        return self

    # The next method will be called repeatedly by the 'for' loop
    # until it raises StopIteration.
    def next(self):
        self.count += 1
        if self.count < 4:
            return self.count
        else:
            # A StopIteration exception is raised
            # to signal that the iterator is done.
            # This is caught implicitly by the 'for' loop.
            raise StopIteration

def some_func():
    return it()

for i in some_func():
    print i

තිරය ​​පිටුපස සිදුවන්නේ කුමක්ද යන්න පිළිබඳ වැඩි අවබෝධයක් සඳහා, forලූපය නැවත ලිවිය හැකිය:

iterator = some_func()
try:
    while 1:
        print iterator.next()
except StopIteration:
    pass

එය වඩාත් අර්ථවත්ද? නැත්නම් ඔබව තව තවත් ව්‍යාකූල කරයිද? :)

මම මේ බව කරුණාවෙන් යුතු වේ නිදර්ශනාත්මක කටයුතු සඳහා යවනසුලූ අතිසරලකරණයකි. :)


1
__getitem__වෙනුවට අර්ථ දැක්විය හැකිය __iter__. උදාහරණයක් ලෙස class it: pass; it.__getitem__ = lambda self, i: i*10 if i < 10 else [][0]; for i in it(): print(i)
:,

17
මම මෙම උදාහරණය පයිතන් 3.6 හි උත්සාහ කළ අතර, මම නිර්මාණය කරන්නේ නම් iterator = some_function(), විචල්‍යයට තවදුරටත් iteratorහැඳින්වෙන ශ්‍රිතයක් නොමැත next(), නමුත් __next__()ශ්‍රිතයක් පමණි . මම ඒක සඳහන් කරන්න හිතුවා.
පීටර්

forඔබ ලියූ ලූප ක්‍රියාත්මක කිරීම ක්ෂණික උදාහරණයේ __iter__ක්‍රමය ලෙස හඳුන්වන්නේ කොතැනින්ද ? iteratorit
ක්‍රමානුකූලව විසුරුවා හැරීම

455

මෙම yieldමූල පදය සරල කරුණු දෙක දක්වා අඩුකර ඇත:

  1. සම්පාදකයා විසින් ශ්‍රිතයක් තුළ ඕනෑම තැනකyield මූල පදය හඳුනාගත හොත් , එම ශ්‍රිතය තවදුරටත් ප්‍රකාශය හරහා ආපසු නොඑයි . ඒ වෙනුවට , එය වහාම එය නැවත කම්මැලි "පොරොත්තු ලේඛනයේ" වස්තුව ජෙනරේටරයක් ලෙසreturn
  2. උත්පාදක යන්ත්රය නැවත කළ හැකිය. නැවත කළ හැකි දේ කුමක්ද? එය එක් එක් මූලද්‍රව්‍යය නිශ්චිත අනුපිළිවෙලකට නැරඹීම සඳහා සාදන ලද ප්‍රොටෝකෝලයක් සහිත, listහෝ setහෝ rangeහෝ දෘෂ්ටිය වැනි දෙයක් වේ.

කෙටියෙන් කිවහොත්: උත්පාදක යන්ත්රය කම්මැලි, වැඩි වැඩියෙන් අපේක්ෂිත ලැයිස්තුවක් වන අතර , උත්පාදක යන්ත්රය වැඩි වැඩියෙන් කෙළ ගැසිය යුතු yieldලැයිස්තු අගයන් වැඩසටහන්ගත කිරීම සඳහා ක්රියාකාරී අංකනය භාවිතා කිරීමට ප්රකාශයන් ඔබට ඉඩ දෙයි .

generator = myYieldingFunction(...)
x = list(generator)

   generator
       v
[x[0], ..., ???]

         generator
             v
[x[0], x[1], ..., ???]

               generator
                   v
[x[0], x[1], x[2], ..., ???]

                       StopIteration exception
[x[0], x[1], x[2]]     done

list==[x[0], x[1], x[2]]

උදාහරණයක්

makeRangeපයිතන්ට සමාන ශ්‍රිතයක් නිර්වචනය කරමු range. නැවත makeRange(n)පැමිණීම ජෙනරේටරය අමතන්න :

def makeRange(n):
    # return 0,1,2,...,n-1
    i = 0
    while i < n:
        yield i
        i += 1

>>> makeRange(5)
<generator object makeRange at 0x19e4aa0>

උත්පාදක list()යන්ත‍්‍රයට එහි ඉතිරිව ඇති අගයන් වහාම ආපසු ලබා දෙන ලෙස බල කිරීම සඳහා, ඔබට එය තුළට යා හැකිය (ඔබට නැවත කළ හැකි ඕනෑම දෙයක් මෙන්):

>>> list(makeRange(5))
[0, 1, 2, 3, 4]

උදාහරණය "ලැයිස්තුවක් ආපසු ලබා දීම" සමඟ සංසන්දනය කිරීම

ඉහත උදාහරණය හුදෙක් ඔබ එකතු කර ආපසු එන ලැයිස්තුවක් නිර්මාණය කිරීමක් ලෙස සිතිය හැකිය:

# list-version                   #  # generator-version
def makeRange(n):                #  def makeRange(n):
    """return [0,1,2,...,n-1]""" #~     """return 0,1,2,...,n-1"""
    TO_RETURN = []               #>
    i = 0                        #      i = 0
    while i < n:                 #      while i < n:
        TO_RETURN += [i]         #~         yield i
        i += 1                   #          i += 1  ## indented
    return TO_RETURN             #>

>>> makeRange(5)
[0, 1, 2, 3, 4]

එක් ප්‍රධාන වෙනසක් ඇත; අවසාන කොටස බලන්න.


ඔබ ජනක යන්ත්‍ර භාවිතා කරන්නේ කෙසේද?

ලැයිස්තුගත අවබෝධයේ අවසාන කොටස නැවත සැකසිය හැකි අතර, සියලු ජනක යන්ත්‍ර නැවත ක්‍රියාත්මක කළ හැකි බැවින් ඒවා බොහෝ විට එසේ භාවිතා වේ:

#                   _ITERABLE_
>>> [x+10 for x in makeRange(5)]
[10, 11, 12, 13, 14]

උත්පාදක යන්ත්ර සඳහා වඩා හොඳ හැඟීමක් ලබා ගැනීම සඳහා, ඔබට itertoolsමොඩියුලය සමඟ සෙල්ලම් කළ හැකිය ( වරෙන්තුවට chain.from_iterableවඩා භාවිතා කිරීමට වග බලා ගන්න chain). උදාහරණයක් ලෙස, වැනි අසීමිත දිගු කම්මැලි ලැයිස්තු ක්‍රියාත්මක කිරීමට ඔබට ජනක යන්ත්‍ර භාවිතා කළ හැකිය itertools.count(). ඔබට ඔබේම දෑ ක්‍රියාත්මක කළ හැකිය def enumerate(iterable): zip(count(), iterable), නැතහොත් විකල්පයක් ලෙස yieldයතුරුපදය සමඟ ටික වේලාවකින් කරන්න.

කරුණාකර සටහන් කරන්න: ජනක යන්ත්‍ර ඇත්ත වශයෙන්ම තවත් බොහෝ දේ සඳහා භාවිතා කළ හැකිය, එනම් කොරෝටයින් ක්‍රියාත්මක කිරීම හෝ නිර්ණායක නොවන වැඩසටහන්කරණය හෝ වෙනත් අලංකාර දේවල්. කෙසේ වෙතත්, මම මෙහි ඉදිරිපත් කරන "කම්මැලි ලැයිස්තු" දෘෂ්ටිකෝණය ඔබ සොයා ගන්නා වඩාත් පොදු භාවිතයයි.


තිරය ​​පිටුපස

"පයිතන් පුනරාවර්තන ප්‍රොටෝකෝලය" ක්‍රියාත්මක වන්නේ එලෙසයි. එනම්, ඔබ කරන විට සිදුවන්නේ කුමක්ද list(makeRange(5)). මෙය මා කලින් විස්තර කළේ "කම්මැලි, වර්ධක ලැයිස්තුවක්" ලෙස ය.

>>> x=iter(range(5))
>>> next(x)
0
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
4
>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

සාදන ලද ශ්‍රිතය next()හුදෙක් වස්තු .next()ශ්‍රිතය ලෙස හඳුන්වන අතර එය “පුනරාවර්තන ප්‍රොටෝකෝලය” හි කොටසක් වන අතර එය සියලු අනුකාරකවල දක්නට ලැබේ. next()විසිතුරු දේවල් ක්‍රියාවට නැංවීම සඳහා ඔබට ශ්‍රිතය (සහ පුනරාවර්තන ප්‍රොටෝකෝලයෙහි වෙනත් කොටස්) භාවිතා කළ හැකිය , සාමාන්‍යයෙන් කියවීමේ වියදමෙන්, එබැවින් එය කිරීමෙන් වැළකී සිටීමට උත්සාහ කරන්න ...


මිනුටියා

සාමාන්‍යයෙන්, බොහෝ අය පහත සඳහන් වෙනස්කම් ගැන තැකීමක් නොකරන අතර බොහෝ විට මෙහි කියවීම නැවැත්වීමට අවශ්‍ය වේ.

පයිතන්- කථාවේදී , පුනරාවර්තනය යනු ලැයිස්තුවක් වැනි “ලූපයක් සඳහා සංකල්පය තේරුම් ගන්නා” ඕනෑම වස්තුවක් වන අතර [1,2,3], ඉරේටරයක් යනු ඉල්ලූ-ලූප් වැනි නිශ්චිත අවස්ථාවකි [1,2,3].__iter__(). ඒ ජනකය එය (කාර්යය කාරක රීති සමග) ලියා තිබුණේ මාර්ගය හැර, ඕනෑම iterator ලෙස හරියටම සමාන වේ.

ඔබ ලැයිස්තුවකින් අනුකාරකයක් ඉල්ලා සිටින විට, එය නව අනුකාරකයක් සාදයි. කෙසේ වෙතත්, ඔබ iterator වෙතින් iterator එකක් ඉල්ලා සිටින විට (ඔබ කලාතුරකින් එය කරනු ඇත), එය ඔබට එහි පිටපතක් ලබා දෙයි.

මේ අනුව, ඔබ මෙවැනි දෙයක් කිරීමට අපොහොසත් වන බවක් නොපෙනෙන අවස්ථාවක ...

> x = myRange(5)
> list(x)
[0, 1, 2, 3, 4]
> list(x)
[]

... එවිට මතක තබා ගන්න උත්පාදක යන්ත්රය අනුකාරකයක් බව ; එනම්, එය එක් වරක් භාවිතා කිරීමකි. ඔබට එය නැවත භාවිතා කිරීමට අවශ්‍ය නම්, ඔබ myRange(...)නැවත අමතන්න . ඔබට ප්‍රති result ලය දෙවරක් භාවිතා කිරීමට අවශ්‍ය නම්, ප්‍රති result ලය ලැයිස්තුවකට පරිවර්තනය කර විචල්‍යයක ගබඩා කරන්න x = list(myRange(5)). පරම (terrifyingly hackish metaprogramming කටයුතු කරමින් සිටින උදාහරණයක් ලෙස,) එක් ජනන යන්ත්රයක පරිගණක ක්රිඩාවට සමාන කිරීමට අවශ්ය අයට භාවිතා කළ හැකි itertools.teeමෙම copyable iterator Python සිට, අත්යවශ්ය නම් පී.ඊ.පී. ප්රමිතීන් යෝජනාව කල් දමනු ලැබ ඇත.


378

මොකක්ද මේ කරන්නේ yieldඉඟි පද Python කරන්න?

ලුහු line ු සටහන් / සාරාංශය

  • ශ්‍රිතයක් yield, කැඳවූ විට, ජනක යන්ත්‍රයක් ලබා දෙයි .
  • උත්පාදක යන්ත්රය අනුකාරක වන්නේ ඒවා අනුකාරක ප්‍රොටෝකෝලය ක්‍රියාත්මක කරන නිසා ඔබට ඒවා හරහා නැවත ක්‍රියා කළ හැකිය.
  • උත්පාදක යන්ත්රයක් ද තොරතුරු යැවිය හැකි අතර එය සංකල්පමය වශයෙන් කෝරෝටීන් බවට පත් කරයි .
  • පයිතන් 3 හි, ඔබට එක් ජනකයකින් තවත් දිශාවකට දෙපැත්තටම පැවරිය හැකිය yield from.
  • (උපග්‍රන්ථය ඉහළම පිළිතුර ඇතුළුව පිළිතුරු කිහිපයක් විවේචනය returnකරන අතර උත්පාදක යන්ත්‍රයක භාවිතය ගැන සාකච්ඡා කරයි .)

ජනක යන්ත්‍ර:

yieldයනු ශ්‍රිත අර්ථ දැක්වීමක නීත්‍යානුකූල ඇතුළත පමණක් වන අතර, ශ්‍රිත අර්ථ දැක්වීමකට ඇතුළත් කිරීමෙන් yieldඑය උත්පාදක යන්ත්‍රයක් ආපසු ලබා දේ.

උත්පාදක යන්ත්ර සඳහා අදහස වෙනත් භාෂාවලින් පැමිණේ (පාද සටහන 1 බලන්න) විවිධ ක්‍රියාත්මක කිරීම් සමඟ. Python හි ඡෙනරේටර් දී, කේතය ඝාතනය කරයි ශීත කළ අස්වැන්න වන ස්ථානෙය් දී. උත්පාදක යන්ත්රය කැඳවූ විට (ක්රම පහත සාකච්ඡා කෙරේ) ක්රියාත්මක කිරීම නැවත ආරම්භ වන අතර ඊළඟ අස්වැන්නෙන් කැටි වේ.

yieldපහත දැක්වෙන ක්‍රම දෙකෙන් අර්ථ දක්වා ඇති iterator ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීමට පහසු ක්‍රමයක් සපයයි : __iter__සහ next(පයිතන් 2) හෝ __next__(පයිතන් 3). මෙම ක්‍රම දෙකම මඟින් මොඩියුලයෙන් Iteratorවියුක්ත පාදක පන්තිය සමඟ ටයිප් කර පරීක්ෂා කළ හැකි වස්තුවක් අනුකාරකයක් බවට පත් කරයි collections.

>>> def func():
...     yield 'I am'
...     yield 'a generator!'
... 
>>> type(func)                 # A function with yield is still a function
<type 'function'>
>>> gen = func()
>>> type(gen)                  # but it returns a generator
<type 'generator'>
>>> hasattr(gen, '__iter__')   # that's an iterable
True
>>> hasattr(gen, 'next')       # and with .next (.__next__ in Python 3)
True                           # implements the iterator protocol.

උත්පාදක වර්ගය අනුකාරකයේ උප වර්ගයකි:

>>> import collections, types
>>> issubclass(types.GeneratorType, collections.Iterator)
True

අවශ්‍ය නම්, අපට මේ ආකාරයට ටයිප් කර පරීක්ෂා කළ හැකිය:

>>> isinstance(gen, types.GeneratorType)
True
>>> isinstance(gen, collections.Iterator)
True

විශේෂාංගයක් නම්, Iterator එය අවසන් වූ පසු , ඔබට එය නැවත භාවිතා කිරීමට හෝ නැවත සැකසීමට නොහැකිය:

>>> list(gen)
['I am', 'a generator!']
>>> list(gen)
[]

ඔබට එහි ක්‍රියාකාරීත්වය නැවත භාවිතා කිරීමට අවශ්‍ය නම් ඔබට තවත් එකක් සෑදීමට සිදුවේ (පාද සටහන 2 බලන්න):

>>> list(func())
['I am', 'a generator!']

කෙනෙකුට ක්‍රමලේඛිකව දත්ත ලබා දිය හැකිය, උදාහරණයක් ලෙස:

def func(an_iterable):
    for item in an_iterable:
        yield item

ඉහත සරල උත්පාදක යන්ත්රය පහත දැක්වෙන දේට සමාන වේ - පයිතන් 3.3 අනුව (සහ පයිතන් 2 හි නොමැත), ඔබට භාවිතා කළ හැකිය yield from:

def func(an_iterable):
    yield from an_iterable

කෙසේ වෙතත්, yield fromඋප-ජනක යන්ත්‍ර වෙත නියෝජිතයින් පැවරීමට ද ඉඩ ලබා දෙන අතර, උප කොරොටින් සමඟ සමුපකාර නියෝජිත කණ්ඩායම පිළිබඳ පහත දැක්වෙන කොටසේ විස්තර කෙරේ.

Coroutines:

yield ජනක යන්ත්‍රයට දත්ත යැවීමට ඉඩ සලසන ප්‍රකාශනයක් සාදයි (පාද සටහන 3 බලන්න)

මෙන්න උදාහරණයක්, receivedවිචල්‍යය සැලකිල්ලට ගන්න , එය ජනක යන්ත්‍රයට යවන දත්ත වෙත යොමු කරයි:

def bank_account(deposited, interest_rate):
    while True:
        calculated_interest = interest_rate * deposited 
        received = yield calculated_interest
        if received:
            deposited += received


>>> my_account = bank_account(1000, .05)

පළමුව, අපි බිල්ඩින් ශ්‍රිතය සමඟ උත්පාදක යන්ත්රය පෝලිම් කළ යුතුය next. ඔබ භාවිතා කරන පයිතන් අනුවාදය මත පදනම්ව එය සුදුසු nextහෝ __next__ක්‍රමවේදය අමතනු ඇත :

>>> first_year_interest = next(my_account)
>>> first_year_interest
50.0

දැන් අපට ජනක යන්ත්‍රයට දත්ත යැවිය හැකිය. ( යැවීම ඇමතුමට Noneසමානnext වේ.):

>>> next_year_interest = my_account.send(first_year_interest + 1000)
>>> next_year_interest
102.5

සමඟ උප-කෝරෝටීන් සඳහා සමුපකාර නියෝජිත කණ්ඩායම yield from

දැන්, yield fromඑය පයිතන් 3 හි ඇති බව සිහිපත් කරන්න .

def money_manager(expected_rate):
    under_management = yield     # must receive deposited value
    while True:
        try:
            additional_investment = yield expected_rate * under_management 
            if additional_investment:
                under_management += additional_investment
        except GeneratorExit:
            '''TODO: write function to send unclaimed funds to state'''
        finally:
            '''TODO: write function to mail tax info to client'''


def investment_account(deposited, manager):
    '''very simple model of an investment account that delegates to a manager'''
    next(manager) # must queue up manager
    manager.send(deposited)
    while True:
        try:
            yield from manager
        except GeneratorExit:
            return manager.close()

දැන් අපට උප උත්පාදක යන්ත්‍රයකට ක්‍රියාකාරීත්වය පැවරිය හැකි අතර එය ඉහත පරිදිම ජනක යන්ත්‍රයකට භාවිතා කළ හැකිය:

>>> my_manager = money_manager(.06)
>>> my_account = investment_account(1000, my_manager)
>>> first_year_return = next(my_account)
>>> first_year_return
60.0
>>> next_year_return = my_account.send(first_year_return + 1000)
>>> next_year_return
123.6

PEP 380yield from හි නිශ්චිත අර්ථ නිරූපණයන් පිළිබඳව ඔබට වැඩිදුර කියවිය හැකිය .

වෙනත් ක්‍රම: වසා දමා විසි කරන්න

මෙම closeක්රමය මතු GeneratorExitවූ අවස්ථාවක දී මෙම උත්සවය ක්රියාත්මක ශීත විය. මෙයද කැඳවනු ලැබේ, __del__එවිට ඔබට හැසිරවිය හැකි ඕනෑම පිරිසිදු කිරීමේ කේතයක් තැබිය හැකිය GeneratorExit:

>>> my_account.close()

උත්පාදක යන්ත්රය තුළ හැසිරවිය හැකි හෝ නැවත පරිශීලකයා වෙත ප්රචාරය කළ හැකි ව්යතිරේකයක් ඔබට විසි කළ හැකිය:

>>> import sys
>>> try:
...     raise ValueError
... except:
...     my_manager.throw(*sys.exc_info())
... 
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "<stdin>", line 2, in <module>
ValueError

නිගමනය

පහත සඳහන් ප්‍රශ්නයේ සියලුම අංග මම ආවරණය කර ඇති බව මම විශ්වාස කරමි.

මොකක්ද මේ කරන්නේ yieldඉඟි පද Python කරන්න?

එය yieldබොහෝ දේ කරයි. මට මීට වඩා ගැඹුරු උදාහරණ එකතු කළ හැකි බව මට විශ්වාසයි. ඔබට තවත් අවශ්‍ය නම් හෝ යම් නිර්මාණාත්මක විවේචනයක් තිබේ නම්, පහත අදහස් දැක්වීමෙන් මට දන්වන්න.


උපග්රන්ථය:

ඉහළ / පිළිගත් පිළිතුර විවේචනය කිරීම **

  • නිදසුනක් ලෙස ලැයිස්තුවක් භාවිතා කරමින් එය නැවත කළ හැකි දේ පිළිබඳ ව්‍යාකූල වේ . ඉහත මගේ විමර්ශන ලිපි බලන්න, නමුත් සාරාංශයෙහි: ක iterable සතුව, __iter__ක නැවත ක්රමය iterator . ක iterator සපයන හා .next(Python 2 හෝ .__next__විසින් නිසැකයෙන්ම යන නමින් නම් කර තිබූ (Python 3) ක්රමය, forඑය මතු කරයි තුරු වළළු StopIteration, සහ එය එක් වරක්, එය දිගටම එසේ කිරීමට වනු ඇත.
  • ඉන්පසු එය ජනක යන්ත්‍රයක් යනු කුමක්දැයි විස්තර කිරීමට උත්පාදක ප්‍රකාශනයක් භාවිතා කරයි. උත්පාදක යන්ත්රය හුදෙක් අනුකාරකයක් සෑදීමට පහසු ක්‍රමයක් බැවින් , එය කාරණය ව්‍යාකූල කිරීම පමණක් වන අතර, අපි තවමත් එම yieldකොටස වෙත පැමිණ නැත .
  • දී එක් ජනන යන්ත්රයක හිඟ වීම පාලනය ඔහු ඉල්ලා .nextක්රමය වෙනුවට ඔහු builtin ක්රියාව භාවිත කළ යුතු විට, next. ඔහුගේ කේතය පයිතන් 3 හි ක්‍රියා නොකරන නිසා එය සුදුසු පරාවර්තක තට්ටුවක් වනු ඇත.
  • ඉටර්ටූල්ස්? මෙය කිසිසේත්ම කරන දෙයට අදාළ නොවේ yield.
  • පයිතන් 3 හි yieldනව ක්‍රියාකාරිත්වය සමඟ සපයන ක්‍රමවේදයන් පිළිබඳ සාකච්ඡාවක් නොමැත. ඉහළ / පිළිගත් පිළිතුර ඉතා අසම්පූර්ණ පිළිතුරකි.yield from

yieldඋත්පාදක ප්‍රකාශනයක හෝ අවබෝධයේ දී යෝජනා කරන පිළිතුරු විවේචනය .

ව්‍යාකරණ දැනට ලැයිස්තු අවබෝධය තුළ ඕනෑම ප්‍රකාශනයකට ඉඩ දෙයි.

expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
                     ('=' (yield_expr|testlist_star_expr))*)
...
yield_expr: 'yield' [yield_arg]
yield_arg: 'from' test | testlist

අස්වැන්න ප්‍රකාශනයක් බැවින්, එය හොඳ අවබෝධයක් හෝ උත්පාදක ප්‍රකාශනයක භාවිතා කිරීමට සමහරුන් උනන්දු කර ඇත - විශේෂයෙන් හොඳ භාවිතයක් නොමැති බව සඳහන් කර තිබියදීත්.

CPython මූලික සංවර්ධකයින් එහි දීමනාව අවලංගු කිරීම පිළිබඳව සාකච්ඡා කරමින් සිටී. තැපැල් ලැයිස්තුවෙන් අදාළ ලිපියක් මෙන්න:

30 ජනවාරි 2017 at 19:05, බ්‍රෙට් කැනන් මෙසේ ලිවීය:

ඉරිදා, 29 ජනවාරි 2017 at 16:39 ක්‍රේග් රොඩ්‍රිගුස් මෙසේ ලිවීය:

එක්කෝ ප්‍රවේශය සමඟ මම හොඳින්. පයිතන් 3 හි ඇති ආකාරයට දේවල් තැබීම හොඳ නැත, IMHO.

මගේ ඡන්දය නම් එය සින්ටැක්ස් දෝෂයකි, මන්ද ඔබ සින්ටැක්ස් වෙතින් බලාපොරොත්තු වන දේ නොලැබෙන බැවිනි.

වර්තමාන හැසිරීම මත රඳා පවතින ඕනෑම කේතයක් නඩත්තු කළ නොහැකි තරම් දක්ෂ බැවින් එය අපට අවසන් කිරීමට සුදුසු ස්ථානයක් බව මම එකඟ වෙමි.

එහි යෑමට අනුව, අපට අවශ්‍ය වනු ඇත්තේ:

  • 3.7 හි සින්ටැක්ස් අනතුරු ඇඟවීම හෝ අවලංගු කිරීමේ අනතුරු ඇඟවීම
  • 2.7.x හි Py3k අනතුරු ඇඟවීම
  • 3.8 හි සින්ටැක්ස් දෝෂය

චියර්ස්, නික්.

- නික් කොග්ලන් | ncoghlan at gmail.com | ඕස්ට්‍රේලියාවේ බ්‍රිස්බේන්

තවද, කැපී පෙනෙන ගැටළුවක් (10544) ඇති අතර එය කිසි විටෙකත් හොඳ අදහසක් නොවන බව පෙනේ (පයිතන් හි ලියා ඇති පයිතන් ක්‍රියාත්මක කිරීම, දැනටමත් සින්ටැක්ස් අනතුරු ඇඟවීම් මතු කරයි.)

බොටම් ලයින්, සීපයිතන් හි සංවර්ධකයින් අපට වෙනත් ආකාරයකින් පවසන තුරු: උත්පාදක ප්‍රකාශනයක් හෝ අවබෝධයක් ලබා නොදෙන්න yield.

මෙම returnඑක් ජනන යන්ත්රයක ප්රකාශයක්

දී Python 2 :

උත්පාදක ශ්‍රිතයකදී, returnප්‍රකාශය ඇතුළත් කිරීමට අවසර නැත expression_list. එම සන්දර්භය තුළ, returnජනක යන්ත්රය සිදු කර ඇති StopIterationඅතර එය ඉහළට ඔසවා තැබීමට හේතු වේ.

An expression_listයනු මූලික වශයෙන් කොමාව මගින් වෙන් කරන ලද ප්‍රකාශන ගණනකි - අත්‍යවශ්‍යයෙන්ම, පයිතන් 2 හි ඔබට උත්පාදක යන්ත්රය නැවැත්විය හැකිය return, නමුත් ඔබට අගයක් ආපසු ලබා දිය නොහැක.

දී Python 3 :

උත්පාදක ශ්‍රිතයකදී, returnප්‍රකාශය මඟින් උත්පාදක යන්ත්රය සිදු කර ඇති StopIterationඅතර එය ඉහළ නැංවීමට හේතු වේ. ආපසු ලබා දුන් අගය (ඇත්නම්) ඉදිකිරීම සඳහා තර්කයක් ලෙස භාවිතා කර ගුණාංගය StopIterationබවට පත්වේ StopIteration.value.

පාද සටහන්

  1. ජනක යන්ත්‍ර සංකල්පය පයිතන්ට හඳුන්වා දීමේ යෝජනාවේ CLU, Sather සහ Icon යන භාෂා සඳහන් කර ඇත. සාමාන්‍ය අදහස නම් ශ්‍රිතයකට අභ්‍යන්තර තත්වය පවත්වා ගෙන යා හැකි අතර පරිශීලකයාගේ ඉල්ලුමට අනුව අතරමැදි දත්ත ලකුණු ලබා දිය හැකිය. සමහර පද්ධතිවල පවා ලබා ගත නොහැකි පයිතන් නූල් ඇතුළු වෙනත් ප්‍රවේශයන්ට වඩා කාර්ය සාධනය වඩා උසස් බවට මෙය පොරොන්දු විය .

  2. නිදසුනක් ලෙස, xrangeවස්තූන් ( rangeපයිතන් 3 හි) ඒවා Iteratorනැවත භාවිතා කළ හැකි බැවින් ඒවා නැවත භාවිතා කළ හැකි වුවද ඒවා නොවේ. ලැයිස්තු මෙන්, ඔවුන්ගේ __iter__ක්‍රම මඟින් iterator වස්තු නැවත ලබා දේ.

  3. yieldමුලින් ප්‍රකාශයක් ලෙස හඳුන්වා දෙන ලදි, එයින් අදහස් වන්නේ එය කේත කොටසක පේළියක ආරම්භයේ පමණක් දිස්විය හැකි බවයි. දැන් yieldඅස්වැන්න ප්‍රකාශනයක් නිර්මාණය කරයි. https://docs.python.org/2/reference/simple_stmts.html#grammar-token-yield_stmt මෙම වෙනස යෝජනා කරනු ලැබුවේ පරිශීලකයාට ලැබිය හැකි ආකාරයටම ජනක යන්ත්‍රයට දත්ත යැවීමට පරිශීලකයාට ඉඩ දීම සඳහා ය. දත්ත යැවීමට, යමෙකුට එය යම් දෙයකට පැවරීමට හැකි විය යුතු අතර, ඒ සඳහා ප්‍රකාශයක් ක්‍රියා නොකරනු ඇත.


329

yieldඑය හරියට return- එය ඔබ පවසන ඕනෑම දෙයක් (ජනක යන්ත්‍රයක් ලෙස) ආපසු ලබා දෙයි. වෙනස වන්නේ ඊළඟ වතාවේ ඔබ උත්පාදක යන්ත්‍රය අමතන විට ක්‍රියාත්මක කිරීම අවසන් ඇමතුමේ සිට yieldප්‍රකාශය දක්වා ආරම්භ වීමයි . නැවත පැමිණීම මෙන් නොව, අස්වැන්නක් සිදු වූ විට තොග රාමුව පිරිසිදු නොකෙරේ, කෙසේ වෙතත් පාලනය නැවත අමතන්නා වෙත මාරු කරනු ලැබේ, එබැවින් ඊළඟ වතාවේ ශ්‍රිතය හැඳින්වූ විට එහි තත්වය නැවත ආරම්භ වේ.

ඔබේ කේතය සම්බන්ධයෙන් ගත් කල, ශ්‍රිතය get_child_candidatesක්‍රියාකරවන්නෙකු මෙන් ක්‍රියා කරයි, එවිට ඔබ ඔබේ ලැයිස්තුව දීර් extend කරන විට, එය වරකට එක් අංගයක් නව ලැයිස්තුවට එක් කරයි.

list.extendඑය අවසන් වන තුරු iterator අමතන්න. ඔබ පළ කළ කේත නියැදිය සම්බන්ධයෙන්, ටුපල් එකක් ආපසු ලබා දී එය ලැයිස්තුවට එකතු කිරීම වඩා පැහැදිලි වනු ඇත.


107
මෙය සමීප නමුත් නිවැරදි නොවේ. අස්වැන්න ප්‍රකාශයක් සහිත ශ්‍රිතයක් ඔබ අමතන සෑම අවස්ථාවකම එය නව උත්පාදක වස්තුවක් ලබා දෙයි. අන්තිම අස්වැන්නෙන් පසු ක්‍රියාත්මක කිරීම නැවත ආරම්භ වන්නේ ඔබ එම උත්පාදක යන්ත්‍රයේ .next () ක්‍රමය අමතන විට පමණි.
kurosch

239

සඳහන් කළ යුතු තවත් එක් දෙයක් තිබේ: අස්වැන්නක් ලබා දෙන ශ්‍රිතයක් ඇත්ත වශයෙන්ම අවසන් කළ යුතු නොවේ. මම මේ වගේ කේතයක් ලියා ඇත:

def fib():
    last, cur = 0, 1
    while True: 
        yield cur
        last, cur = cur, last + cur

එවිට මට මෙය වෙනත් කේතයකින් භාවිතා කළ හැකිය:

for f in fib():
    if some_condition: break
    coolfuncs(f);

එය සැබවින්ම සමහර ගැටලු සරල කිරීමට උපකාරී වන අතර සමහර දේවල් සමඟ වැඩ කිරීම පහසු කරයි.


234

අවම වැඩ කරන උදාහරණයකට කැමති අය සඳහා, මෙම අන්තර්ක්‍රියාකාරී පයිතන් සැසිය ගැන මෙනෙහි කරන්න:

>>> def f():
...   yield 1
...   yield 2
...   yield 3
... 
>>> g = f()
>>> for i in g:
...   print(i)
... 
1
2
3
>>> for i in g:
...   print(i)
... 
>>> # Note that this time nothing was printed

209

ටීඑල්; ඩී.ආර්

මේ වෙනුවට:

def square_list(n):
    the_list = []                         # Replace
    for x in range(n):
        y = x * x
        the_list.append(y)                # these
    return the_list                       # lines

මෙය කරන්න:

def square_yield(n):
    for x in range(n):
        y = x * x
        yield y                           # with this one.

ඔබ මුල සිටම ලැයිස්තුවක් ගොඩනඟන විට, yieldඒ වෙනුවට එක් එක් කැබැල්ල.

අස්වැන්න සහිත මගේ පළමු "අහා" මොහොත මෙයයි.


yieldයනු සීනි කියන්න ක්රමයක්

දේවල් මාලාවක් සාදන්න

එකම හැසිරීම:

>>> for square in square_list(4):
...     print(square)
...
0
1
4
9
>>> for square in square_yield(4):
...     print(square)
...
0
1
4
9

වෙනස් හැසිරීම:

අස්වැන්න තනි පාස් ය : ඔබට නැවත වරක් කළ හැක්කේ එක් වරක් පමණි. ශ්‍රිතයකට අස්වැන්නක් ඇති විට අපි එය උත්පාදක ශ්‍රිතයක් ලෙස හඳුන්වමු . හා iterator එය නැවත දේ. එම කොන්දේසි හෙළි කරයි. අපට කන්ටේනරයක පහසුව නැති වී යයි, නමුත් අවශ්‍ය පරිදි ගණනය කරන ලද සහ අත්තනෝමතික ලෙස දිගු කරන ලද ශ්‍රේණියක බලය ලබා ගනී.

අස්වැන්න කම්මැලි ය , එය ගණනය කිරීම කල් දමයි. එහි අස්වැන්නක් සහිත ශ්‍රිතයක් ඔබ එය අමතන විට එය කිසිසේත් ක්‍රියාත්මක නොවේ. එය නැවතී ගිය වස්තුව සිහිපත් කරන iterator වස්තුවක් නැවත ලබා දෙයි . ඔබ next()පුනරාවර්තකය අමතන සෑම අවස්ථාවකම (මෙය සිදුවන්නේ ලූපයක් සඳහා) ඊළඟ අස්වැන්න සඳහා අඟල් ඉදිරියට. returnStopIteration මතු කර ශ්‍රේණිය අවසන් කරයි (මෙය for-loop එකක ස්වාභාවික අවසානයයි).

අස්වැන්න බහුකාර්ය වේ. දත්ත සියල්ලම එකට ගබඩා කළ යුතු නැත, එය එකවර ලබා ගත හැකිය. එය අනන්ත විය හැකිය.

>>> def squares_all_of_them():
...     x = 0
...     while True:
...         yield x * x
...         x += 1
...
>>> squares = squares_all_of_them()
>>> for _ in range(4):
...     print(next(squares))
...
0
1
4
9

ඔබට බහු අවසර පත්‍ර අවශ්‍ය නම් සහ ශ්‍රේණිය දිගු නොවේ නම්, එය අමතන්න list():

>>> list(square_yield(4))
[0, 1, 4, 9]

අර්ථ දෙකම අදාළ වන yieldනිසා වචනයේ දීප්තිමත් තේරීම :

අස්වැන්න - නිෂ්පාදනය හෝ සැපයීම (කෘෂිකර්මාන්තයේ මෙන්)

... මාලාවේ ඊළඟ දත්ත සපයන්න.

අස්වැන්න - (දේශපාලන බලයේ දී මෙන්) ඉඩ දෙන්න හෝ අත්හරින්න

... iterator ඉදිරියට යන තුරු CPU ක්‍රියාත්මක කිරීම අත්හරින්න.


194

අස්වැන්න ඔබට ජනක යන්ත්‍රයක් ලබා දෙයි.

def get_odd_numbers(i):
    return range(1, i, 2)
def yield_odd_numbers(i):
    for x in range(1, i, 2):
       yield x
foo = get_odd_numbers(10)
bar = yield_odd_numbers(10)
foo
[1, 3, 5, 7, 9]
bar
<generator object yield_odd_numbers at 0x1029c6f50>
bar.next()
1
bar.next()
3
bar.next()
5

ඔබට පෙනෙන පරිදි, පළමු අවස්ථාවේ fooදී මුළු ලැයිස්තුවම එකවර මතකයේ තබා ගනී. මූලද්රව්ය 5 ක් සහිත ලැයිස්තුවක් සඳහා එය විශාල ගනුදෙනුවක් නොවේ, නමුත් ඔබට මිලියන 5 ක ලැයිස්තුවක් අවශ්ය නම් කුමක් කළ යුතුද? මෙය විශාල මතක අනුභව කරන්නෙකු පමණක් නොව, ශ්‍රිතය හැඳින්වෙන අවස්ථාවේ ගොඩ නැගීමට විශාල කාලයක් වැය වේ.

දෙවන අවස්ථාවේදී, barඔබට උත්පාදක යන්ත්රයක් ලබා දෙයි. උත්පාදක යන්ත්රය නැවත කළ හැකි ය - එයින් අදහස් කරන්නේ ඔබට එය forපුඩුවක් තුළ භාවිතා කළ හැකි ය, නමුත් සෑම අගයක්ම ලබා ගත හැක්කේ එක් වරක් පමණි. සියලුම අගයන් එකවර මතකයේ ගබඩා නොවේ; උත්පාදක වස්තුව ඔබ එය අවසන් වරට හැඳින්වූ ස්ථානය "මතක තබා ගනී" - මේ ආකාරයෙන්, ඔබ (කියන්නට) බිලියන 50 ක් දක්වා පුනරාවර්තනයක් භාවිතා කරන්නේ නම්, ඔබට සියල්ල බිලියන 50 ක් ලෙස ගණන් ගත යුතු නැත එකවර ගණනය කර ගණන් කිරීමට බිලියන 50 ක සංඛ්‍යා ගබඩා කරන්න.

නැවතත්, මෙය ඉතා ව්‍යාකූල උදාහරණයකි, ඔබට ඇත්ත වශයෙන්ම බිලියන 50 ක් ගණන් කිරීමට අවශ්‍ය නම් ඔබ බොහෝ විට ඉටර්ටූල් භාවිතා කරනු ඇත. :)

උත්පාදක යන්ත්රවල වඩාත් සරල භාවිත අවස්ථාව මෙයයි. ඔබ පැවසූ පරිදි, එය යම් ආකාරයක සිරස් විචල්‍යයක් භාවිතා කරනවා වෙනුවට ඇමතුම් තොගය හරහා දේවල් ඉහළට තල්ලු කිරීම සඳහා අස්වැන්න භාවිතා කරමින් කාර්යක්ෂම ප්‍රේර්‍ය ලිවීමට භාවිතා කළ හැකිය. විශේෂිත ගස් ගමන් කිරීම සහ අනෙකුත් සියලු දේ සඳහා ජනක යන්ත්‍ර භාවිතා කළ හැකිය.


සටහනක් පමණක් - පයිතන් 3 හි, rangeලැයිස්තුවක් වෙනුවට උත්පාදක යන්ත්රයක් ද ලබා දෙයි, එබැවින් ඔබට සමාන අදහසක් පෙනෙනු ඇත, හැරෙන්නට __repr__/ __str__වඩා හොඳ ප්රති result ලයක් පෙන්වීමට අභිබවා ගොස් ඇත, මේ අවස්ථාවේ දී range(1, 10, 2).
නොටාලි.

189

එය නැවත ජනක යන්ත්‍රයක් යවයි. මම විශේෂයෙන් පයිතන් ගැන හුරුපුරුදු නැත, නමුත් මම විශ්වාස කරන්නේ ඔබ ඒවා හුරු පුරුදු නම් එය සී # ඉටරේටර් බ්ලොක් වලට සමාන බවයි.

ප්‍රධාන අදහස නම්, සම්පාදකයා / පරිවර්තකයා / යම් උපක්‍රමයක් කරන නිසා ඇමතුම්කරුට අදාළව ඔවුන්ට ඊළඟ () ඇමතුම ලබා ගත හැකි අතර එය නැවත අගයන් ලබා දෙනු ඇත - උත්පාදක ක්‍රමය විරාමයක් මෙන් . දැන් පැහැදිලිවම ඔබට ක්‍රමයක් "විරාමයක්" කළ නොහැක, එබැවින් ඔබ දැනට සිටින්නේ කොතැනද සහ දේශීය විචල්‍යයන් වැනි දේ මතක තබා ගැනීම සඳහා සම්පාදකයා විසින් රාජ්‍ය යන්ත්‍රයක් සාදයි. මෙය තනිවම ලිවීමට වඩා පහසුය.


167

උත්පාදක යන්ත්ර භාවිතා කරන්නේ කෙසේද යන්න විස්තර කරන බොහෝ විශිෂ්ට පිළිතුරු අතර, මට තවම ලබා දී නොමැති පිළිතුරක් තිබේ. ක්‍රමලේඛන භාෂා න්‍යාය පිළිතුර මෙන්න:

මෙම yieldපිඹුරා ප්රකාශයක් එක් ජනන යන්ත්රයක පැමිණේ. පයිතන්හි උත්පාදක යන්ත්රය යනු අඛණ්ඩව ලබා දෙන ශ්‍රිතයකි (සහ විශේෂයෙන් කොරොටින් වර්ගයකි, නමුත් අඛණ්ඩව සිදුවන්නේ කුමක් දැයි තේරුම් ගැනීමට වඩාත් පොදු යාන්ත්‍රණයයි).

ක්‍රමලේඛන භාෂා න්‍යායේ අඛණ්ඩතාව යනු වඩාත් මූලික ආකාරයේ ගණනය කිරීමකි, නමුත් ඒවා බොහෝ විට භාවිතා නොකෙරේ, මන්ද ඒවා ගැන තර්ක කිරීම අතිශයින් දුෂ්කර වන අතර ක්‍රියාත්මක කිරීමට ඉතා අපහසුය. නමුත් අඛණ්ඩව යනු කුමක්ද යන්න පිළිබඳ අදහස සරල ය: එය තවමත් අවසන් වී නැති ගණනය කිරීමක තත්වයයි. මෙම තත්වය තුළ, විචල්‍යයන්ගේ වත්මන් අගයන්, තවමත් සිදු කර නොමැති මෙහෙයුම් සහ යනාදිය සුරකිනු ලැබේ. පසුව යම් අවස්ථාවක දී වැඩසටහනේ අඛණ්ඩතාවය ක්‍රියාත්මක කළ හැකිය, එනම් වැඩසටහනේ විචල්‍යයන් එම තත්වයට යලි සකසනු ලබන අතර සුරකින ලද මෙහෙයුම් සිදු කරනු ලැබේ.

අඛණ්ඩව, මෙම වඩාත් පොදු ස්වරූපයෙන්, ආකාර දෙකකින් ක්‍රියාත්මක කළ හැකිය. තුළ call/ccමාර්ගය, වැඩසටහනේ අඩුක්කුව වචනාර්ථයෙන් ගැලවීම හා පසුව අඛණ්ඩව පළ කළහ විට, අඩුක්කුව පත් වෙයි.

අඛණ්ඩව සම්මත කිරීමේ ශෛලියේ (සීපීඑස්), අඛණ්ඩතාව යනු සාමාන්‍ය කාර්යයන් පමණි (ශ්‍රිත පළමු පන්තියේ භාෂාවලින් පමණි), ක්‍රමලේඛකයා පැහැදිලිවම කළමනාකරණය කර සබ්ට්‍රවුටින් වෙත ගමන් කරයි. මෙම ශෛලිය තුළ, ක්‍රමලේඛ තත්වය නිරූපණය කරන්නේ තොගයේ කොතැනක හෝ වාසය කරන විචල්‍යයන්ට වඩා වසා දැමීම් (සහ ඒවා තුළ කේතනය කර ඇති විචල්‍යයන්) ය. පාලක ප්‍රවාහය කළමනාකරණය කරන කාර්යයන් අඛණ්ඩව තර්ක ලෙස පිළිගනී (සීපීඑස් හි සමහර වෙනස්කම් වලදී, කාර්යයන් බහු අඛණ්ඩතාවයන් පිළිගත හැකිය) සහ පාලක ප්‍රවාහය හසුරුවන්නේ ඒවා කැඳවීමෙන් පසුව නැවත පැමිණීමෙනි. අඛණ්ඩ සම්මත ශෛලිය පිළිබඳ ඉතා සරල උදාහරණයක් පහත පරිදි වේ:

def save_file(filename):
  def write_file_continuation():
    write_stuff_to_file(filename)

  check_if_file_exists_and_user_wants_to_overwrite(write_file_continuation)

මෙම (ඉතා සරල) උදාහරණයේ දී, ක්‍රමලේඛකයා සත්‍ය වශයෙන්ම ගොනුව අඛණ්ඩව ලිවීමේ ක්‍රියාකාරිත්වය සුරකිනු ඇත (එය ලිවීමට බොහෝ විස්තර සහිත ඉතා සංකීර්ණ මෙහෙයුමක් විය හැකිය), ඉන්පසු එම අඛණ්ඩතාව පසු කරයි (එනම්, පළමු- පංති වසා දැමීම) තවත් සැකසුම් කරන වෙනත් ක්‍රියාකරුවෙකු වෙත, පසුව අවශ්‍ය නම් එය අමතන්න. .

මෙම ලිපියේ ඉතිරි කොටස සාමාන්‍ය භාවය නැති නොකර අඛණ්ඩව සීපීඑස් ලෙස සංකල්පනය කරනු ඇත, මන්ද එය තේරුම් ගැනීමට සහ කියවීමට පහසු නිරයක් වන බැවිනි.


දැන් අපි පයිතන්හි ජනක යන්ත්‍ර ගැන කතා කරමු. උත්පාදක යන්ත්ර යනු අඛණ්ඩතාවයේ නිශ්චිත උප වර්ගයකි. ඇති ෙහයින්ද continuations වූ රාජ්ය බේරා ගැනීමට පොදුවේ හැකි ගණනය (එනම්, මෙම වැඩසටහන තුළින් ඇමතුමක් අඩුක්කුව), ජනක යන්ත්ර පමණක් කට පුනහ්කරණයක් රාජ්ය බේරා ගැනීමට හැකි iterator . කෙසේ වෙතත්, මෙම නිර්වචනය ජනක යන්ත්‍රවල ඇතැම් භාවිත අවස්ථා සඳහා තරමක් නොමඟ යවන සුළුය. උදාහරණයක් වශයෙන්:

def f():
  while True:
    yield 4

මෙය පැහැදිලිවම සාධාරණ ක්‍රියාකාරී ක්‍රියාවලියක් වන අතර ඔවුන්ගේ හැසිරීම මනාව නිර්වචනය කර ඇත - උත්පාදක යන්ත්රය එය හරහා නැවත ක්‍රියාත්මක වන සෑම අවස්ථාවකම එය 4 ක් ආපසු ලබා දෙයි (එය සදහටම සිදු වේ). නමුත් එය බොහෝ විට අනුකාරක (එනම්, for x in collection: do_something(x)) ගැන සිතන විට මතකයට එන්නේ මූලාකෘති වර්ගය නොවේ . මෙම උදාහරණයෙන් ජනක යන්ත්‍රවල බලය විදහා දක්වයි: යමක් අනුකාරකයක් නම්, උත්පාදක යන්ත්‍රයකට එහි ක්‍රියාකාරීත්වයේ තත්වය සුරැකිය හැක.

නැවත අවධාරණය කිරීම සඳහා: අඛණ්ඩතාව මඟින් වැඩසටහනක තොගයේ තත්වය සුරැකිය හැකි අතර උත්පාදක යන්ත‍්‍රයන්ට පුනරාවර්තන තත්ත්වය සුරැකිය හැක. මෙයින් අදහස් කරන්නේ අඛණ්ඩව උත්පාදක යන්ත්ර වලට වඩා බලවත් වන අතර ජනක යන්ත්ර ගොඩක් පහසු වන බවයි. ඒවා භාෂා නිර්මාණකරුට ක්‍රියාත්මක කිරීමට පහසු වන අතර ඒවා ක්‍රමලේඛකයාට භාවිතා කිරීම පහසුය (ඔබට පිළිස්සීමට යම් කාලයක් තිබේ නම්, අඛණ්ඩතාව සහ ඇමතුම් / සීසී ගැන මෙම පිටුව කියවා තේරුම් ගැනීමට උත්සාහ කරන්න ).

නමුත් අඛණ්ඩ සම්මත ශෛලිය පිළිබඳ සරල, නිශ්චිත අවස්ථාවක් ලෙස ඔබට පහසුවෙන් ජනක යන්ත්‍ර ක්‍රියාත්මක කළ හැකිය (සහ සංකල්පනය කළ හැකිය):

yieldකැඳවූ සෑම අවස්ථාවකම , එය අඛණ්ඩව නැවත ලබා දෙන ලෙස ශ්‍රිතයට කියයි. ශ්‍රිතය නැවත කැඳවූ විට, එය ආරම්භ වූ තැන සිට ආරම්භ වේ. එබැවින්, ව්‍යාජ-ව්‍යාජ කේතයේ (එනම් ව්‍යාජ කේතයක් නොව කේතයක් නොවේ) උත්පාදක nextක්‍රමය මූලික වශයෙන් පහත පරිදි වේ:

class Generator():
  def __init__(self,iterable,generatorfun):
    self.next_continuation = lambda:generatorfun(iterable)

  def next(self):
    value, next_continuation = self.next_continuation()
    self.next_continuation = next_continuation
    return value

මෙහි yieldමූලික පදය සැබෑ උත්පාදක ශ්‍රිතය සඳහා සින්ටැක්ටික් සීනි වේ.

def generatorfun(iterable):
  if len(iterable) == 0:
    raise StopIteration
  else:
    return (iterable[0], lambda:generatorfun(iterable[1:]))

මෙය ව්‍යාජ කේතයක් පමණක් බවත් පයිතන්හි ජනක යන්ත්‍ර සත්‍ය වශයෙන්ම ක්‍රියාත්මක කිරීම වඩාත් සංකීර්ණ බවත් මතක තබා ගන්න. නමුත් සිදුවන්නේ කුමක්ද යන්න වටහා ගැනීමේ අභ්‍යාසයක් ලෙස, යතුරුපදය භාවිතා නොකර උත්පාදක වස්තු ක්‍රියාත්මක කිරීම සඳහා අඛණ්ඩ සම්මත ශෛලිය භාවිතා කිරීමට උත්සාහ කරන්න yield.


152

මෙන්න සරල භාෂාවෙන් උදාහරණයක්. මම ඉහළ මට්ටමේ මානව සංකල්ප අතර පහත් මට්ටමේ පයිතන් සංකල්ප අතර ලිපි හුවමාරුවක් ලබා දෙන්නෙමි.

මට සංඛ්‍යා අනුක්‍රමයක් මත ක්‍රියා කිරීමට අවශ්‍යයි, නමුත් එම අනුක්‍රමය නිර්මාණය කිරීම ගැන මගේ ආත්මයට කරදර වීමට මට අවශ්‍ය නැත, මට අවශ්‍ය වන්නේ මට කිරීමට අවශ්‍ය මෙහෙයුම කෙරෙහි පමණක් අවධානය යොමු කිරීමයි. එබැවින්, මම පහත සඳහන් දේ කරමි:

  • මම ඔබට කතා කර ඔබට නිශ්චිත ආකාරයකින් නිපදවන සංඛ්‍යා මාලාවක් අවශ්‍ය බව ඔබට කියමි, ඇල්ගොරිතම යනු කුමක්දැයි මම ඔබට දන්වමි.
    මෙම පියවර defඋත්පාදක ශ්‍රිතයට අනුරූප වේ, එනම් a අඩංගු ශ්‍රිතය yield.
  • ටික වේලාවකට පසු, මම ඔබට කියමි, "හරි, සංඛ්‍යා අනුපිළිවෙල මට කියන්න සූදානම් වෙන්න".
    මෙම පියවර උත්පාදක වස්තුවක් ලබා දෙන උත්පාදක ශ්‍රිතය ඇමතීමට අනුරූප වේ. ඔබ තවමත් මට කිසිදු අංකයක් නොකියන බව සලකන්න; ඔබ ඔබේ කඩදාසි සහ පැන්සල අල්ලා ගන්න.
  • මම ඔබෙන් අහනවා, "ඊළඟ අංකය මට කියන්න", ඔබ මට පළමු අංකය කියන්න; ඊට පසු, ඔබ ඊළඟ අංකය ඔබෙන් ඉල්ලා සිටින තෙක් ඔබ බලා සිටින්න. ඔබ සිටි ස්ථානය, ඔබ දැනටමත් පවසා ඇති අංක සහ ඊළඟ අංකය කුමක්ද යන්න මතක තබා ගැනීම ඔබේ කාර්යය වේ. මම විස්තර ගැන තැකීමක් කරන්නේ නැහැ.
    මෙම පියවර .next()උත්පාදක වස්තුව ඇමතීමට අනුරූප වේ .
  • … පෙර පියවර නැවත කරන්න, තෙක්…
  • අවසානයේදී, ඔබ අවසානයකට පැමිණිය හැකිය. ඔබ මට අංකයක් නොකියයි; ඔබ කෑ ගසන්නේ, "ඔබේ අශ්වයන් අල්ලාගෙන සිටින්න! මම ඉවරයි! තවත් අංක නැත!"
    මෙම පියවර උත්පාදක වස්තුවට සිය කාර්යය අවසන් වන අතර StopIterationව්‍යතිරේකයක් මතු කරයි උත්පාදක ශ්‍රිතයට ව්‍යතිරේකය ඉහළ නැංවීමට අවශ්‍ය නොවේ. ශ්‍රිතය අවසන් වූ විට හෝ නිකුත් කරන විට එය ස්වයංක්‍රීයව මතු වේ return.

උත්පාදක යන්ත්රය කරන්නේ මෙයයි (a අඩංගු ශ්‍රිතයක් yield); එය ක්‍රියාත්මක කිරීමට පටන් ගනී, එය කරන සෑම විටම විරාමයක් ලබා දෙයි yield, සහ .next()අගයක් ඉල්ලූ විට එය අවසන් මොහොතේ සිටම පවතී. අනුපිළිවෙලින් අගයන් ඉල්ලා සිටින ආකාරය විස්තර කරන පයිතන්හි අනුකාරක ප්‍රොටෝකෝලය සමඟ එය හොඳින් ගැලපේ.

Iterator ප්‍රොටෝකෝලයෙහි වඩාත්ම ප්‍රසිද්ධ පරිශීලකයා වන්නේ forපයිතන් හි විධානයයි. එබැවින්, ඔබ එය කරන සෑම අවස්ථාවකම:

for item in sequence:

ඉහත විස්තර කර ඇති ආකාරයට sequenceලැයිස්තුවක්, නූලක්, ශබ්ද කෝෂයක් හෝ උත්පාදක වස්තුවක් නම් එය ගැටළුවක් නොවේ ; ප්‍රති result ලය එක හා සමානයි: ඔබ අනුපිළිවෙලින් අයිතම එකින් එක කියවයි.

යතුරු පදයක් defඅඩංගු ශ්‍රිතයක් ආරම්භ yieldකිරීම උත්පාදක යන්ත්‍රයක් නිර්මාණය කිරීමට ඇති එකම ක්‍රමය නොවන බව සලකන්න . එය නිර්මාණය කිරීමට ඇති පහසුම ක්‍රමයයි.

වඩාත් නිවැරදි තොරතුරු සඳහා, පයිතන් ප්‍රලේඛනයේ ඇති iterator වර්ග , අස්වැන්න ප්‍රකාශය සහ උත්පාදක යන්ත්‍ර ගැන කියවන්න.


130

yieldඋත්පාදක යන්ත්රයක් සෑදීමට ඔබ භාවිතා කරන්නේ ඇයිදැයි බොහෝ පිළිතුරු පෙන්වන නමුත්, ඒ සඳහා වැඩි භාවිතයන් ඇත yield. කෝරොටින් සෑදීම තරමක් පහසු වන අතර එමඟින් කේත කොටස් දෙකක් අතර තොරතුරු සම්ප්‍රේෂණය කළ හැකිය. yieldඋත්පාදක යන්ත්රයක් සෑදීම සඳහා භාවිතා කිරීම පිළිබඳව දැනටමත් ලබා දී ඇති කදිම උදාහරණ කිසිවක් මම නැවත නොකරමි .

yieldපහත දැක්වෙන කේතයේ ඇති දේ තේරුම් ගැනීමට උපකාර කිරීම සඳහා , ඔබට ඇති ඕනෑම කේතයක් හරහා චක්‍රය සොයා ගැනීමට ඔබේ ඇඟිල්ල භාවිතා කළ හැකිය yield. සෑම අවස්ථාවකදීම ඔබේ ඇඟිල්ල බීලී yield, ඔබ එන තෙක් බලා සිටීමට සිදුවනු nextහෝ sendඇතුළත් කළ. nextඇමතුමක් ලබා දුන් විට , ඔබ පහර දෙන තෙක් කේතය සොයා ගනී yield… දකුණු පස ඇති කේතය yieldඇගයීමට ලක් කර නැවත අමතන්නා වෙත… එවිට ඔබ රැඳී සිටින්න. nextනැවත කැඳවූ විට , ඔබ කේතය හරහා තවත් ලූපයක් සිදු කරයි. කෙසේ වෙතත්, ඔබ coroutine දී, බව කරුණාවෙන් කරන්නම් yieldසමග ද භාවිතා කළ හැක send... මෙම දුරකථන ඇමතුම සිට අගය එවන බවට අදහස උත්සවය. A sendලබා දෙන්නේ නම්, එසේ නම්yieldයවන ලද අගය ලබාගෙන එය වම් පැත්තෙන් කෙළ ගසයි… ඉන්පසු ඔබ yieldනැවත පහර දෙන තෙක් කේතය හරහා හෝඩුවාව ඉදිරියට යයි (අවසානයේ අගය කැඳවූවාක් මෙන් next).

උදාහරණයක් වශයෙන්:

>>> def coroutine():
...     i = -1
...     while True:
...         i += 1
...         val = (yield i)
...         print("Received %s" % val)
...
>>> sequence = coroutine()
>>> sequence.next()
0
>>> sequence.next()
Received None
1
>>> sequence.send('hello')
Received hello
2
>>> sequence.close()

හුරුබුහුටි! ඒ trampoline (වූ ළිස්ප් අර්ථයෙන්). බොහෝ විට කිසිවෙකු ඒවා දකින්නේ නැත!
00prometheus

129

තවත් yieldභාවිතයක් සහ අර්ථයක් ඇත (පයිතන් 3.3 සිට):

yield from <expr>

PEP 380 සිට - උප උත්පාදක යන්ත්‍රයකට පැවරීමේ වාක්‍ය ඛණ්ඩය :

උත්පාදක යන්ත්රයක් එහි මෙහෙයුම් වලින් කොටසක් වෙනත් ජනක යන්ත්රයකට පැවරීම සඳහා සින්ටැක්ස් එකක් යෝජනා කරයි. 'අස්වැන්න' අඩංගු කේතයේ කොටසක් සාධක කර වෙනත් ජනක යන්ත්‍රයක තැබීමට මෙය ඉඩ දෙයි. මීට අමතරව, උප උත්පාදක යන්ත්‍රයට අගයක් සමඟ ආපසු යාමට අවසර දී ඇති අතර, එම අගය නියෝජිත ජනක යන්ත්‍රයට ලබා දේ.

නව සින්ටැක්ස් මඟින් එක් ජනක යන්ත්‍රයක් තවත් නිෂ්පාදිත අගයන් නැවත ලබා දෙන විට ප්‍රශස්තිකරණය සඳහා අවස්ථා කිහිපයක් විවෘත කරයි.

තවද මෙය හඳුන්වා දෙනු ඇත (පයිතන් 3.5 සිට):

async def new_coroutine(data):
   ...
   await blocking_action()

සාමාන්‍ය ජනක යන්ත්‍රයක් සමඟ කොරෝටීන් ව්‍යාකූල වීම වළක්වා ගැනීම සඳහා (අද yieldමේ දෙකෙහිම භාවිතා වේ).


117

සියලු හොඳ පිළිතුරු, කෙසේ වෙතත් නවකයින්ට ටිකක් අපහසුයි.

මම හිතන්නේ ඔබ එම returnප්‍රකාශය ඉගෙන ගෙන ඇති බවයි.

සාදෘශ්යයක් ලෙස, returnහා yieldනිවුන් දරුවන් වේ. return'ආපසු පැමිණීම සහ නැවැත්වීම' යන්නෙහි අර්ථය වන අතර 'අස්වැන්න' යන්නෙහි තේරුම 'ආපසු පැමිණීම, නමුත් ඉදිරියට යාම'

  1. සමඟ අංක_ ලැයිස්තුවක් ලබා ගැනීමට උත්සාහ කරන්න return.
def num_list(n):
    for i in range(n):
        return i

එය ක්‍රියාත්මක කරන්න:

In [5]: num_list(3)
Out[5]: 0

බලන්න, ඔබට ලැබෙන්නේ ඒවායේ ලැයිස්තුවකට වඩා එක් අංකයක් පමණි. returnකිසි විටෙකත් ඔබට සතුටින් ජය ගැනීමට ඉඩ නොදෙන්න, එක් වරක් ක්‍රියාත්මක කර ඉවත් වන්න.

  1. එනවා yield

returnසමඟ ප්රතිස්ථාපනය කරන්න yield:

In [10]: def num_list(n):
    ...:     for i in range(n):
    ...:         yield i
    ...:

In [11]: num_list(3)
Out[11]: <generator object num_list at 0x10327c990>

In [12]: list(num_list(3))
Out[12]: [0, 1, 2]

දැන්, ඔබ සියලු අංක ලබා ගැනීමට ජය ගනී.

returnඑක් වරක් ධාවනය වන සහ නතර වන, yieldඔබ සැලසුම් කළ වාර ගණන සමඟ සැසඳීම . ඔබට , සහ ලෙස අර්ථ returnදැක්විය හැකිය . මෙය හැඳින්වේ .return one of themyieldreturn all of themiterable

  1. තවත් එක් පියවරක් සමඟ අපට yieldප්‍රකාශය නැවත ලිවිය හැකියreturn
In [15]: def num_list(n):
    ...:     result = []
    ...:     for i in range(n):
    ...:         result.append(i)
    ...:     return result

In [16]: num_list(3)
Out[16]: [0, 1, 2]

එහි හරය yieldඑයයි.

ලැයිස්තු returnප්‍රතිදානයන් සහ වස්තු yieldප්‍රතිදානය අතර වෙනස:

ඔබට සැමවිටම [0, 1, 2] ලැයිස්තු වස්තුවකින් ලැබෙනු ඇත, නමුත් ඒවා ලබා ගත හැක්කේ 'වස්තු yieldප්‍රතිදානයෙන්' එක් වරක් පමණි. එබැවින්, එහි දැක්වෙන පරිදි නව නාම generatorවස්තුවක් ඇත Out[11]: <generator object num_list at 0x10327c990>.

අවසාන වශයෙන්, එය උකහා ගැනීමේ රූපකයක් ලෙස:

  • returnසහ yieldනිවුන් දරුවන් ය
  • listසහ generatorනිවුන් දරුවන් ය

මෙය තේරුම්ගත හැකි නමුත් එක් ප්‍රධාන වෙනසක් නම් ඔබට ශ්‍රිතයක් / ක්‍රමයක් තුළ බහු අස්වැන්නක් ලබා ගත හැකිය. එම අවස්ථාවේ දී ප්‍රතිසමතාව මුළුමනින්ම බිඳ වැටේ. අස්වැන්න ශ්‍රිතයක එහි ස්ථානය සිහිපත් කරයි, එබැවින් ඊළඟ වතාවේ ඔබ ඊළඟ () අමතන විට ඔබේ ක්‍රියාකාරිත්වය ඊළඟට ඉදිරියට යයි yield. මෙය වැදගත්, මම සිතන අතර එය ප්‍රකාශ කළ යුතුය.
මයික් එස්

104

උත්පාදක යන්ත්ර ඇත්ත වශයෙන්ම ක්රියාත්මක කරන්නේ කෙසේද යන්න පිළිබඳ පයිතන් උදාහරණ කිහිපයක් මෙන්න: පයිතන් ඒවා සඳහා සින්ටැක්ටික් සීනි ලබා දී නැත:

පයිතන් උත්පාදකයක් ලෙස:

from itertools import islice

def fib_gen():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b

assert [1, 1, 2, 3, 5] == list(islice(fib_gen(), 5))

උත්පාදක යන්ත්ර වෙනුවට ශබ්දකෝෂ වසා දැමීම

def ftake(fnext, last):
    return [fnext() for _ in xrange(last)]

def fib_gen2():
    #funky scope due to python2.x workaround
    #for python 3.x use nonlocal
    def _():
        _.a, _.b = _.b, _.a + _.b
        return _.a
    _.a, _.b = 0, 1
    return _

assert [1,1,2,3,5] == ftake(fib_gen2(), 5)

උත්පාදක යන්ත්ර වෙනුවට වස්තු වසා දැමීම භාවිතා කිරීම (මන්ද ClosuresAndObjectsAreEquivalent )

class fib_gen3:
    def __init__(self):
        self.a, self.b = 1, 1

    def __call__(self):
        r = self.a
        self.a, self.b = self.b, self.a + self.b
        return r

assert [1,1,2,3,5] == ftake(fib_gen3(), 5)

97

මම "ජනක යන්ත්‍ර පිළිබඳ ඉක්මන් විස්තරයක් සඳහා බීස්ලිගේ 'පයිතන්: අත්‍යවශ්‍ය යොමු කිරීම' හි 19 වන පිටුව කියවීමට ගියෙමි, නමුත් තවත් බොහෝ අය දැනටමත් හොඳ විස්තර පළ කර ඇත.

තවද, yieldඋත්පාදක ක්‍රියාකාරිත්වයේ ද්විත්ව භාවිතය ලෙස කොරොටින් භාවිතා කළ හැකි බව සලකන්න . එය ඔබගේ කේත ස්නිපටයට සමාන භාවිතයක් නොවුනත්, (yield)ශ්‍රිතයක ප්‍රකාශනයක් ලෙස භාවිතා කළ හැකිය. අමතන්නා විසින් ක්‍රමවේදය භාවිතා කර send()ක්‍රමයට අගයක් යවන විට , ඊළඟ (yield)ප්‍රකාශය හමු වන තෙක් කොරොටින් ක්‍රියාත්මක වේ.

ජනක යන්ත්‍ර සහ කොරෝටීන් යනු දත්ත ප්‍රවාහ වර්ගයේ යෙදුම් සැකසීමට සිසිල් ක්‍රමයකි. yieldකාර්යයේ දී ප්‍රකාශයේ අනෙක් භාවිතය ගැන දැන ගැනීම වටී යැයි මම සිතුවෙමි .


97

ක්‍රමලේඛන දෘෂ්ටි කෝණයකින්, අනුකාරක ක්‍රියාත්මක කරනු ලබන්නේ කටුක ලෙස ය .

සමගාමීව ක්‍රියාත්මක කිරීම සඳහා ඉරේටර, උත්පාදක යන්ත්‍ර සහ නූල් තටාක ආදිය ක්‍රියාත්මක කිරීම සඳහා යමෙක් වසා දැමීමේ වස්තුවකට යවන ලද පණිවිඩ භාවිතා කරයි.

http://en.wikipedia.org/wiki/Message_passing

" ඊළඟ " යනු වසා දැමීමකට යවන ලද පණිවිඩයකි, එය " iter " ඇමතුම මගින් නිර්මාණය කරන ලදි .

මෙම ගණනය කිරීම ක්රියාත්මක කිරීමට බොහෝ ක්රම තිබේ. මම විකෘතිය භාවිතා කළෙමි, නමුත් වර්තමාන අගය සහ ඊළඟ යෙල්ඩර් ආපසු ලබා දීමෙන් විකෘතියකින් තොරව එය කිරීම පහසුය.

මෙන්න R6RS හි ව්‍යුහය භාවිතා කරන නිරූපණයක්, නමුත් අර්ථ නිරූපණය පයිතන්ට සම්පූර්ණයෙන්ම සමාන ය. එය එකම ගණනය කිරීමේ ආකෘතියක් වන අතර එය පයිතන් හි නැවත ලිවීමට අවශ්‍ය වන්නේ වාක්‍ය ඛණ්ඩයේ වෙනසක් පමණි.

Welcome to Racket v6.5.0.3.

-> (define gen
     (lambda (l)
       (define yield
         (lambda ()
           (if (null? l)
               'END
               (let ((v (car l)))
                 (set! l (cdr l))
                 v))))
       (lambda(m)
         (case m
           ('yield (yield))
           ('init  (lambda (data)
                     (set! l data)
                     'OK))))))
-> (define stream (gen '(1 2 3)))
-> (stream 'yield)
1
-> (stream 'yield)
2
-> (stream 'yield)
3
-> (stream 'yield)
'END
-> ((stream 'init) '(a b))
'OK
-> (stream 'yield)
'a
-> (stream 'yield)
'b
-> (stream 'yield)
'END
-> (stream 'yield)
'END
->

84

මෙන්න සරල උදාහරණයක්:

def isPrimeNumber(n):
    print "isPrimeNumber({}) call".format(n)
    if n==1:
        return False
    for x in range(2,n):
        if n % x == 0:
            return False
    return True

def primes (n=1):
    while(True):
        print "loop step ---------------- {}".format(n)
        if isPrimeNumber(n): yield n
        n += 1

for n in primes():
    if n> 10:break
    print "wiriting result {}".format(n)

ප්‍රතිදානය:

loop step ---------------- 1
isPrimeNumber(1) call
loop step ---------------- 2
isPrimeNumber(2) call
loop step ---------------- 3
isPrimeNumber(3) call
wiriting result 3
loop step ---------------- 4
isPrimeNumber(4) call
loop step ---------------- 5
isPrimeNumber(5) call
wiriting result 5
loop step ---------------- 6
isPrimeNumber(6) call
loop step ---------------- 7
isPrimeNumber(7) call
wiriting result 7
loop step ---------------- 8
isPrimeNumber(8) call
loop step ---------------- 9
isPrimeNumber(9) call
loop step ---------------- 10
isPrimeNumber(10) call
loop step ---------------- 11
isPrimeNumber(11) call

මම පයිතන් සංවර්ධකයෙකු නොවේ, නමුත් එය මට පෙනෙන්නේ yieldවැඩසටහන් ප්‍රවාහයේ පිහිටීම සහ ඊළඟ ලූපය "අස්වැන්න" ස්ථානයෙන් ආරම්භ වන බවයි. එය එම ස්ථානයේ රැඳී සිටින බවක් පෙනේ, ඊට පෙර, පිටත වටිනාකමක් ආපසු ලබා දීම, ඊළඟ වතාවේ දිගටම වැඩ කිරීම.

එය සිත්ගන්නාසුළු හා හොඳ හැකියාවක් බව පෙනේ: ඩී


ඔබ හරි. නමුත් “අස්වැන්න” හි හැසිරීම දැකීමට ප්‍රවාහයට ඇති බලපෑම කුමක්ද? මට ගණිතයේ නාමයෙන් ඇල්ගොරිතම වෙනස් කළ හැකිය. "අස්වැන්න" පිළිබඳ වෙනස් තක්සේරුවක් ලබා ගැනීමට එය උපකාරී වේද?
එන්ජින් OZTURK

68

මෙන්න කරන්නේ කුමක්ද යන්න පිළිබඳ මානසික ප්‍රතිරූපයක් yield.

නූල් පොකුරක් ඇති බව සිතීමට මම කැමතියි (එය එසේ ක්‍රියාත්මක නොවූ විට පවා).

සාමාන්‍ය ශ්‍රිතයක් හැඳින්වූ විට, එය එහි දේශීය විචල්‍යයන් තොගයේ තබයි, යම් ගණනය කිරීමක් කරයි, පසුව තොගය ඉවත් කර නැවත පැමිණේ. එහි දේශීය විචල්‍යයන්ගේ අගයන් නැවත කිසි දිනෙක දක්නට නොලැබේ.

yieldශ්‍රිතයක් සමඟ , එහි කේතය ක්‍රියාත්මක වීමට පටන් ගත් විට (එනම් ශ්‍රිතය හැඳින්වීමෙන් පසු, උත්පාදක වස්තුවක් ආපසු ලබා දීම, එහි next()ක්‍රමය පසුව ආයාචනා කරනු ලැබේ), ඒ හා සමානව එහි දේශීය විචල්‍යයන් තොගයට දමා ටික වේලාවක් ගණනය කරයි. නමුත් පසුව, එය yieldප්‍රකාශයට පහර දෙන විට , එහි කොටස ඉවත් කර නැවත පැමිණීමට පෙර, එය එහි දේශීය විචල්‍යයන්ගේ ඡායාරූපයක් ගෙන ඒවා උත්පාදක වස්තුව තුළ ගබඩා කරයි. එය දැනට එහි කේතයේ දක්වා ඇති ස්ථානය ද ලියයි (එනම් විශේෂිත yieldප්‍රකාශය).

එබැවින් එය උත්පාදක යන්ත්රය මත එල්ලා ඇති ශීත කළ ශ්‍රිතයකි.

පසුව next()කැඳවූ විට , එය ශ්‍රිතයේ බඩු තොගය ගබඩාවට ලබා ගෙන එය නැවත සජීවිකරණය කරයි. ශ්‍රිතය සදාකාලිකවම සීතල ගබඩා කිරීම සඳහා වැය කර ඇති බව නොසලකා හරිමින්, එය නතර කළ තැන සිට ගණනය කිරීම දිගටම කරගෙන යයි.

පහත උදාහරණ සසඳා බලන්න:

def normalFunction():
    return
    if False:
        pass

def yielderFunction():
    return
    if False:
        yield 12

අපි දෙවන ශ්‍රිතය අමතන විට එය පළමු එකට වඩා වෙනස් ලෙස හැසිරේ. මෙම yieldප්රකාශය ළඟාවිය නොහැකි විය හැක, නමුත් එය දැනට ඕනෑම තැනක තියෙන්නේ නම්, එය අප සමඟ කටයුතු කරන්නේ කුමක් ස්වභාවය වෙනස් වෙනවා.

>>> yielderFunction()
<generator object yielderFunction at 0x07742D28>

ඇමතීමෙන් yielderFunction()එහි කේතය ක්‍රියාත්මක නොවේ, නමුත් උත්පාදක යන්ත්‍රයක් කේතයෙන් ඉවත් කරයි. (සමහර විට yielderකියවීමේ හැකියාව සඳහා උපසර්ගය සමඟ එවැනි දේ නම් කිරීම හොඳ අදහසකි .)

>>> gen = yielderFunction()
>>> dir(gen)
['__class__',
 ...
 '__iter__',    #Returns gen itself, to make it work uniformly with containers
 ...            #when given to a for loop. (Containers return an iterator instead.)
 'close',
 'gi_code',
 'gi_frame',
 'gi_running',
 'next',        #The method that runs the function's body.
 'send',
 'throw']

මෙම gi_codeසහ gi_frameශීත කළ රාජ්ය ගබඩා කර ඇත එහිදී ක්ෂේත්ර වේ. ඒවා ගවේෂණය කිරීමෙන් dir(..)ඉහත අපගේ මානසික ආකෘතිය විශ්වසනීය බව අපට තහවුරු කළ හැකිය.


59

සෑම පිළිතුරක්ම යෝජනා කරන පරිදි, yieldඅනුක්‍රමික උත්පාදක යන්ත්‍රයක් නිර්මාණය කිරීම සඳහා භාවිතා වේ. කිසියම් අනුක්‍රමයක් ගතිකව ජනනය කිරීම සඳහා එය භාවිතා කරයි. උදාහරණයක් ලෙස, ජාලයක රේඛීයව ගොනු රේඛාවක් කියවන අතරතුර, ඔබට yieldශ්‍රිතය පහත පරිදි භාවිතා කළ හැකිය :

def getNextLines():
   while con.isOpen():
       yield con.read()

ඔබට එය පහත පරිදි ඔබේ කේතයෙන් භාවිතා කළ හැකිය:

for line in getNextLines():
    doSomeThing(line)

ක්‍රියාත්මක කිරීමේ පාලන මාරු ගොචා

forඅස්වැන්න ක්‍රියාත්මක වන විට ක්‍රියාත්මක කිරීමේ පාලනය getNextLines () සිට ලූපයට මාරු කරනු ලැබේ . මේ අනුව, getNextLines () ආයාචනා කරන සෑම අවස්ථාවකම, ක්‍රියාත්මක කිරීම ආරම්භ වන්නේ එය අවසන් වරට විරාම කළ ස්ථානයේ සිට ය.

කෙටියෙන් කිවහොත්, පහත කේතය සමඟ ශ්‍රිතයක්

def simpleYield():
    yield "first time"
    yield "second time"
    yield "third time"
    yield "Now some useful value {}".format(12)

for i in simpleYield():
    print i

මුද්‍රණය කරයි

"first time"
"second time"
"third time"
"Now some useful value 12"

59

එය කුමක්දැයි වටහා ගැනීමට පහසු උදාහරණයක්: yield

def f123():
    for _ in range(4):
        yield 1
        yield 2


for i in f123():
    print (i)

ප්‍රතිදානය:

1 2 1 2 1 2 1 2

5
එම ප්‍රතිදානය ගැන ඔබට විශ්වාසද? ඔබ එම මුද්‍රණ ප්‍රකාශය භාවිතයෙන් ධාවනය කළහොත් එය තනි පේළියක පමණක් මුද්‍රණය කළ print(i, end=' ')නොහැකිද? එසේ නොමැතිනම්, පෙරනිමි හැසිරීම මඟින් සෑම
අංකයක්ම

90 user9074332, ඔබ හරි, නමුත් එය තේරුම් ගැනීමට පහසු වන පරිදි එක පේළියක ලියා ඇත
ගැව්රියෙල් කොහෙන්

57

(පිළිතුර පහත මගේ පමණක් නොව Python ජනකය භාවිතා කිරීමේ ඉදිරිදර්ශනය, සිට කතා ජනකය යාන්ත්රණයක් යටින් ක්රියාත්මක අඩුක්කුව සහ ගොඩක් හැසිරවීම සමහර උපක්රම ඇතුළත් වන,.)

පයිතන් ශ්‍රිතයක් yieldවෙනුවට භාවිතා කරන විට return, එම ශ්‍රිතය විශේෂ දෙයක් ලෙස හැඳින්වේ generator function. එම ශ්‍රිතය generatorවර්ගයේ වස්තුවක් නැවත ලබා දෙනු ඇත . මෙම yieldමූල පදය විශේෂයෙන් කාර්ය ප්රතිකාර කිරීම සඳහා මෙම පිඹුරා සම්පාදක වෙත දැනුම්දීම ධජ වේ. යම් අගයක් එයින් ආපසු ලබා දුන් පසු සාමාන්‍ය කාර්යයන් අවසන් වේ. නමුත් සම්පාදකයාගේ ආධාරයෙන් උත්පාදක ක්‍රියාකාරිත්වය නැවත ආරම්භ කළ හැකි යැයි සිතිය හැකිය . එනම්, ක්‍රියාත්මක කිරීමේ සන්දර්භය ප්‍රතිෂ් ored ාපනය වන අතර අවසන් වරට ක්‍රියාත්මක කිරීම දිගටම කරගෙන යනු ඇත. ඔබ පැහැදිලිවම නැවත ඇමතුමක් ලබා දෙන තුරු, එය StopIterationව්‍යතිරේකයක් මතු කරයි (එය අනුකාරක ප්‍රොටෝකෝලයෙහි කොටසක් ද වේ), නැතහොත් ශ්‍රිතයේ අවසානය කරා ළඟා වේ. මම මේ ගැන සඳහන් කිරීම් ගොඩක් සොයා generatorනමුත් මේ එකසිට functional programming perspectiveවඩාත්ම ජීර්ණය කළ හැකි ය.

(දැන් මට අවශ්‍ය වන්නේ පිටුපස ඇති තාර්කිකත්වය generatorසහ iteratorමගේ අවබෝධය මත පදනම් වූවකි. මෙය අනුකාරකයේ සහ උත්පාදක යන්ත්‍රයේ අත්‍යවශ්‍ය අභිප්‍රේරණය ග්‍රහණය කර ගැනීමට ඔබට උපකාරී වනු ඇතැයි මම බලාපොරොත්තු වෙමි .

මට තේරෙන පරිදි, අපට දත්ත පොකුරක් සැකසීමට අවශ්‍ය වූ විට, අපි සාමාන්‍යයෙන් දත්ත කොතැනක හෝ ගබඩා කර පසුව එකින් එක සැකසෙමු. නමුත් මෙම බොළඳ ප්‍රවේශය ගැටළු සහගතය. දත්ත පරිමාව අති විශාල නම්, ඒවා කල්තියා ගබඩා කිරීම මිල අධිකය. එබැවින් dataඑය කෙලින්ම ගබඩා කරනවා වෙනුවට , යම් ආකාරයක metadataවක්‍රව ගබඩා නොකරන්නේ මන්ද , එනම්the logic how the data is computed .

එවැනි පාර-දත්ත එතීමට ප්‍රවේශයන් 2 ක් ඇත.

  1. OO ප්රවේශය, අපි පාර-දත්ත ඔතා as a class. iteratorඅනුකාරක ප්‍රොටෝකෝලය (එනම් __next__(), සහ __iter__()ක්‍රම) ක්‍රියාත්මක කරන්නේ ඊනියා ය . මෙයද බහුලව දැකිය හැකි iterator සැලසුම් රටාවයි .
  2. ක්‍රියාකාරී ප්‍රවේශය, අපි පාර-දත්ත ඔතා as a function. මෙය ඊනියා ය generator function. නමුත් කබාය යටතේ, ආපසු එන generator objectනිශ්චල IS-Aක්‍රියාකාරකය එය iterator ප්‍රොටෝකෝලය ද ක්‍රියාත්මක කරන බැවිනි.

කෙසේ හෝ වේවා, අනුකාරකයක් සාදනු ලැබේ, එනම් ඔබට අවශ්‍ය දත්ත ලබා දිය හැකි යම් වස්තුවකි. OO ප්රවේශය ටිකක් සංකීර්ණ විය හැකිය. කෙසේ වෙතත්, කුමන එකක් භාවිතා කළ යුතුද යන්න ඔබට භාරයි.


54

සාරාංශයක් ලෙස, yieldප්‍රකාශය මඟින් ඔබේ ශ්‍රිතය කර්මාන්ත ශාලාවක් බවට පරිවර්තනය කරන generatorඅතර එය ඔබේ මුල් ශ්‍රිතයේ ශරීරය වටා එතෙන විශේෂ වස්තුවක් නිපදවයි . වූ විට generatorශාඛාවයි වේ, එය ඉදිරි පත්වන තෙක් එය ඔබගේ කාර්යය ඉටු yieldකිරීමට සමත් වටිනා ක්රියාත්මක ඇගයීමට අත්හිටුවයි පසුව yield. ක්‍රියාත්මක කිරීමේ මාවත ශ්‍රිතයෙන් පිටවන තුරු එය එක් එක් නැවතීමේ ක්‍රියාවලිය මත මෙම ක්‍රියාවලිය නැවත සිදු කරයි. උදාහරණයක් වශයෙන්,

def simple_generator():
    yield 'one'
    yield 'two'
    yield 'three'

for i in simple_generator():
    print i

සරලව ප්‍රතිදානය කරයි

one
two
three

බලය ලැබෙන්නේ අනුක්‍රමයක් ගණනය කරන ලූපයක් සමඟ උත්පාදක යන්ත්රය භාවිතා කිරීමෙනි, උත්පාදක යන්ත්රය ගණනය කිරීමේ ඊළඟ ප්රති result ලය 'අස්වැන්න' ලබා ගැනීම සඳහා සෑම අවස්ථාවකදීම ලූපය නතර කරයි, මේ ආකාරයෙන් එය මැස්සන්ගේ ලැයිස්තුවක් ගණනය කරයි, වාසිය මතකය විශේෂයෙන් විශාල ගණනය කිරීම් සඳහා සුරකින ලදි

නැවත rangeකළ හැකි සංඛ්‍යා පරාසයක් නිපදවන ඔබේම ශ්‍රිතයක් නිර්මාණය කිරීමට ඔබට අවශ්‍ය යැයි පවසන්න , ඔබට එය එසේ කළ හැකිය,

def myRangeNaive(i):
    n = 0
    range = []
    while n < i:
        range.append(n)
        n = n + 1
    return range

එය මේ ආකාරයට භාවිතා කරන්න;

for i in myRangeNaive(10):
    print i

නමුත් මෙය අකාර්යක්ෂමයි

  • ඔබ එක් වරක් පමණක් භාවිතා කරන අරාවක් සාදයි (මෙය මතකය නාස්ති කරයි)
  • මෙම කේතය ඇත්ත වශයෙන්ම එම අරාව දෙවරක් ලූප කරයි! :(

වාසනාවකට මෙන් ගයිඩෝ සහ ඔහුගේ කණ්ඩායම ජනක යන්ත්‍ර නිපදවීමට තරම් ත්‍යාගශීලී වූ බැවින් අපට මෙය කළ හැකිය.

def myRangeSmart(i):
    n = 0
    while n < i:
       yield n
       n = n + 1
    return

for i in myRangeSmart(10):
    print i

දැන් එක් එක් පුනරාවර්තනයේදී උත්පාදක යන්ත්රයෙහි next()ශ්‍රිතයක් ක්‍රියාත්මක වන අතර එය 'අස්වැන්න' ප්‍රකාශයක් වෙත ළඟා වන තෙක් එය නවත්වන අතර එහි අගය 'ලබා දෙයි' හෝ ශ්‍රිතයේ අවසානය දක්වා ළඟා වේ. මෙම අවස්ථාවෙහිදී, පළමු ඇමතුමේදී, next()අස්වැන්න ප්‍රකාශය දක්වා ක්‍රියාත්මක වන අතර 'n' අස්වැන්න ලබා දෙනු ඇත, ඊළඟ ඇමතුමේදී එය වර්ධක ප්‍රකාශය ක්‍රියාත්මක කරනු ඇත, නැවත 'අතරට' පනින්න, එය ඇගයීමට ලක් කරයි, සහ සත්‍ය නම් එය නතර වනු ඇත නැවත 'n' අස්වැන්න ලබා දෙන්න, තත්වය අසත්‍ය වන අතර උත්පාදක යන්ත්රය ශ්‍රිතයේ අවසානය දක්වා පනින තෙක් එය දිගටම පවතිනු ඇත.


53

අස්වැන්න යනු වස්තුවකි

returnශ්‍රිතයක A තනි අගයක් ලබා දෙනු ඇත.

විශාල අගයන් සමූහයක් ආපසු ලබා දීමට ඔබට ශ්‍රිතයක් අවශ්‍ය නම් , භාවිතා කරන්න yield.

වැදගත්ම yieldදෙය නම් බාධකයකි .

CUDA භාෂාවේ ඇති බාධකයක් මෙන්, එය සම්පූර්ණ වන තුරු එය පාලනය මාරු නොකරනු ඇත.

එනම්, එය ආරම්භයේ සිට එය ක්‍රියාත්මක වන තෙක් ඔබේ ශ්‍රිතයේ කේතය ක්‍රියාත්මක කරයි yield. එවිට, එය ලූපයේ පළමු අගය නැවත ලබා දෙනු ඇත.

එවිට, අනෙක් සෑම ඇමතුමක්ම ඔබ ශ්‍රිතයේ ලියා ඇති ලූපය තවත් වරක් ක්‍රියාත්මක කර නැවත පැමිණීමට කිසිදු වටිනාකමක් නොමැති තෙක් ඊළඟ අගය නැවත ලබා දෙනු ඇත.


52

බොහෝ අය භාවිතා returnකරනවාට වඩා භාවිතා කරයි yield, නමුත් සමහර අවස්ථාවල yieldවඩා කාර්යක්ෂම හා වැඩ කිරීමට පහසු විය හැකිය.

yieldඅනිවාර්යයෙන්ම හොඳම උදාහරණය මෙන්න :

ආපසු (ක්‍රියාකාරී වේ)

import random

def return_dates():
    dates = [] # With 'return' you need to create a list then return it
    for i in range(5):
        date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"])
        dates.append(date)
    return dates

අස්වැන්න (ක්‍රියාත්මක වේ)

def yield_dates():
    for i in range(5):
        date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"])
        yield date # 'yield' makes a generator automatically which works
                   # in a similar way. This is much more efficient.

ඇමතුම් කාර්යයන්

dates_list = return_dates()
print(dates_list)
for i in dates_list:
    print(i)

dates_generator = yield_dates()
print(dates_generator)
for i in dates_generator:
    print(i)

කාර්යයන් දෙකම එකම දේ කරයි, නමුත් yieldපහක් වෙනුවට පේළි තුනක් භාවිතා කරන අතර කරදර වීමට අඩු විචල්‍යයක් ඇත.

කේතයේ ප්‍රති result ලය මෙයයි:

ප්‍රතිදානය

ඔබට පෙනෙන පරිදි කාර්යයන් දෙකම එකම දේ කරයි. එකම වෙනස වන්නේ return_dates()ලැයිස්තුවක් yield_dates()ලබා දීම සහ උත්පාදක යන්ත්රය ලබා දීමයි.

සැබෑ ජීවිත උදාහරණයක් වනුයේ ලිපිගොනු පේළියක් කියවීම හෝ ඔබට උත්පාදක යන්ත්‍රයක් සෑදීමට අවශ්‍ය නම් ය.


43

yieldයනු ශ්‍රිතයක් සඳහා ආපසු එන අංගයකි. වෙනස නම්, yieldමූලද්‍රව්‍යය ශ්‍රිතයක් ජනක යන්ත්‍රයක් බවට පත් කිරීමයි. යම් දෙයක් 'අස්වැන්නක්' ලැබෙන තුරු උත්පාදක යන්ත්රයක් ක්‍රියා කරයි. උත්පාදක යන්ත්රය ඊළඟට කැඳවන තුරු නතර වන අතර එය ආරම්භ වූ ස්ථානයේ සිටම පවතී. ඇමතීමෙන් ඔබට සියලු 'අස්වැන්න' අගයන් අනුපිළිවෙලක් ලබා ගත හැකිය list(generator()).



36

yieldෆයිබොනාච්චි ශ්‍රේණිය ගණනය කිරීම සඳහා සරල පදනම් කරගත් ප්‍රවේශයක් මෙන්න :

def fib(limit=50):
    a, b = 0, 1
    for i in range(limit):
       yield b
       a, b = b, a+b

ඔබ මෙය ඔබේ REPL වෙත ඇතුළු කර එය උත්සාහ කර ඇමතූ විට, ඔබට අද්භූත ප්‍රති result ලයක් ලැබෙනු ඇත:

>>> fib()
<generator object fib at 0x7fa38394e3b8>

මෙයට හේතුව yieldඔබට උත්පාදක යන්ත්‍රයක් නිර්මාණය කිරීමට අවශ්‍ය පයිතන්ට සං aled ා කිරීම , එනම් ඉල්ලුමට අනුව අගයන් ජනනය කරන වස්තුවකි.

ඉතින්, ඔබ මෙම අගයන් ජනනය කරන්නේ කෙසේද? මෙය සෘජුවම කළ හැක්කේ බිල්ට් ශ්‍රිතය භාවිතා කිරීමෙන් nextහෝ වක්‍රව එය අගයන් පරිභෝජනය කරන ඉදිකිරීමකට පෝෂණය කිරීමෙනි.

සාදන ලද next()ශ්‍රිතය භාවිතා කරමින් , ඔබ කෙලින්ම ආයාචනා කරයි .next/ __next__, උත්පාදක යන්ත්‍රයට වටිනාකමක් නිපදවීමට බල කරයි:

>>> g = fib()
>>> next(g)
1
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
>>> next(g)
5

වක්රව ලබා දීම ඔබට fibකිරීමට forපුඩුවක්, එය listinitializer, එය tupleinitializer, හෝ අපේක්ෂා කරන බව ජනනය කරන වස්තුවක් / වටිනාකම් නිෂ්පාදනය වෙන කිසිම දෙයක්, ඔබ ජනකය තවත් වටිනාකම් එය ඉදිරිපත් කළ හැකි වන තෙක් "පරිභෝජනය" එන්නම් (සහ එය නැවත) :

results = []
for i in fib(30):       # consumes fib
    results.append(i) 
# can also be accomplished with
results = list(fib(30)) # consumes fib

ඒ හා සමානව, tupleආරම්භකයක් සමඟ :

>>> tuple(fib(5))       # consumes fib
(1, 1, 2, 3, 5)

උත්පාදක යන්ත්‍රයක් කම්මැලිකම යන අර්ථයෙන් ශ්‍රිතයකට වඩා වෙනස් වේ. එය සිදු කරන්නේ එහි ප්‍රාදේශීය තත්වය පවත්වා ගෙන යාමෙන් සහ ඔබට අවශ්‍ය විටෙක නැවත ආරම්භ කිරීමට ඉඩ දීමෙනි.

ඔබ fibඑය ඇමතීමෙන් පළමු වරට ඉල්ලූ විට:

f = fib()

පයිතන් ශ්‍රිතය සම්පාදනය කරයි, yieldමූල පදය හමු වී උත්පාදක වස්තුවක් ඔබ වෙත ආපසු ලබා දෙයි. එය එතරම් ප්‍රයෝජනවත් නොවේ.

ඔබ එය ඉල්ලූ විට එය පළමු අගය සෘජුව හෝ වක්‍රව ජනනය කරයි, එය සොයා ගන්නා සියලු ප්‍රකාශ ක්‍රියාත්මක කරයි, එය හමු වන තුරු එය yieldඔබ ලබා දුන් අගය නැවත ලබා දෙයි yield. මෙය වඩා හොඳින් නිරූපණය කරන උදාහරණයක් සඳහා, අපි printඇමතුම් කිහිපයක් භාවිතා කරමු ( print "text"පයිතන් 2 හි නම් ආදේශ කරන්න ):

def yielder(value):
    """ This is an infinite generator. Only use next on it """ 
    while 1:
        print("I'm going to generate the value for you")
        print("Then I'll pause for a while")
        yield value
        print("Let's go through it again.")

දැන්, REPL හි ඇතුළත් කරන්න:

>>> gen = yielder("Hello, yield!")

ඔබට උත්පාදක වස්තුවක් ඇත, එය වටිනාකමක් ජනනය කිරීම සඳහා විධානයක් බලාපොරොත්තුවෙන් සිටී. nextමුද්‍රණය කර ඇති දේ භාවිතා කර බලන්න:

>>> next(gen) # runs until it finds a yield
I'm going to generate the value for you
Then I'll pause for a while
'Hello, yield!'

නොකියවූ ප්‍රති results ල මුද්‍රණය කර ඇති දේ වේ. උපුටා ගත් ප්‍රති result ලය වන්නේ ආපසු ලබා දෙන දෙයයි yield. nextදැන් නැවත අමතන්න :

>>> next(gen) # continues from yield and runs again
Let's go through it again.
I'm going to generate the value for you
Then I'll pause for a while
'Hello, yield!'

උත්පාදක යන්ත්රය එය නවතා ඇති බව සිහිපත් කර yield valueඑතැන් සිට නැවත ආරම්භ වේ. ඊළඟ පණිවිඩය මුද්‍රණය කර ඇති yieldඅතර එය විරාමයක් ලබා ගැනීම සඳහා වූ ප්‍රකාශය නැවත ක්‍රියාත්මක කිරීම ( whileලූපය හේතුවෙන් ).

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.