Генераторлар: итерацияны басқару және жадты үнемдеу
Generator (computer programming)
Генераторлар – компьютер ғылымында цикл итерациясын басқаруға арналған процедура. Аз жад қолданып, деректерді біртіндеп шығарады, итератор ретінде жұмыс істейді.
Ағылшыншамен салыстырыңыз: абзацты басыңыз — түпнұсқа терезеде ашылады. Абзац астындағы EN түймесі оны мәтін ішінде көрсетеді.
Мазмұны
Кіріспе
Компьютерлік ғылымда генератор – циклдың итерациялық мінез-құлқын басқаруға қолданылатын процедура. Барлық генераторлар сонымен қатар итераторлар болып табылады. Генератор массивті қайтаратын функцияға өте ұқсас, оның параметрлері бар, оны шақыруға болады және мәндер тізбегін жасайды. Дегенмен, барлық мәндерді қамтитын массив құрып, оларды бірден қайтарудың орнына, генератор мәндерді біртіндеп шығарып береді, бұл аз жадты қажет етеді және шақырушыға алғашқы бірнеше мәндерді дереу өңдеуге мүмкіндік береді. Қысқасы, генератор функция сияқты көрінеді, бірақ итератор сияқты жұмыс істейді. Генераторларды корутиналар немесе бірінші дәрежелі жалғаулар сияқты күштірек басқару ағыны құрылымдары арқылы жүзеге асыруға болады. Генераторлар, жартылай корутиналар деп те аталады, корутиналардың ерекше жағдайы (және одан әлсіз), себебі олар әрқашан шақырушыға басқаруды қайтарады (мәнді қайтарғанда), корутинаға секіруді көрсетудің орнына; корутиналар мен генераторларды салыстыруға қараңыз.
In computer science, a generator is a routine that can be used to control the iteration behaviour of a loop. All generators are also iterators. A generator is very similar to a function that returns an array, in that a generator has parameters, can be called, and generates a sequence of values. However, instead of building an array containing all the values and returning them all at once, a generator yields the values one at a time, which requires less memory and allows the caller to get started processing the first few values immediately. In short, a generator looks like a function but behaves like an iterator. Generators can be implemented in terms of more expressive control flow constructs, such as coroutines or first class continuations. Generators, also known as semicoroutines, are a special case of (and weaker than) coroutines, in that they always yield control back to the caller (when passing a value back), rather than specifying a coroutine to jump to; see comparison of coroutines with generators.
Қолданылуы
Генераторлар әдетте циклдер ішінде шақырылады. Генераторды циклде алғаш рет кездестіргенде, итератор нысаны құрылады, ол генератордың бастапқы күйін және сәйкес параметрлерге байланысты аргументтерді қамтиды. Генератордың коды арнайы yield әрекетіне кездескенше осы итератордың контекстінде орындалады; сол кезде yield әрекетімен берілген мән шақыру өрнегінің мәні ретінде қолданылады. Келесі рет келесі итерацияда сол генератор шақырылғанда, генератордың коды yield әрекетінен кейін жалғастырылады, басқа yield әрекетіне кездеспейінше. Yield әрекетінен басқа, генератордың коды finish әрекетімен де тоқтатылуы мүмкін, онда генераторды шақыруды қоршаған ішкі цикл аяқталады. Күрделірек жағдайларда генератор итератор жасау үшін циклдің сыртында қолмен пайдаланылуы мүмкін, одан кейін оны әртүрлі тәсілдермен қолдануға болады. Генераторлар өнімдерін тек қажет болғанда ғана есептейтіндіктен, олар бірден есептеу қиын немесе мүмкін емес тізбектер сияқты ағындарды көрсету үшін пайдалы. Мұндайларға, мысалы, шексіз тізбектер және деректердің тікелей ағындары жатады. Егер дереу бағалау қажет болса (әсіресе тізбек шекті болғанда, әйтпесе бағалау ешқашан аяқталмайды), оны тізімге түрлендіруге немесе генератордың орнына тізім құратын параллель құрылымды пайдалануға болады. Мысалы, Python-да генератор g-ді l = list(g) арқылы тізімге түрлендіруге болады, ал F#-да seq { } тізбек өрнегі жалқау түрде (генератор немесе тізбек) бағаланады, бірақ [ ] дереу (тізім) бағаланады. Генераторлардың болуы тілдің циклдық құрылымдарын, мысалы for және while, бір циклдік құрылымға дейін азайтуға мүмкіндік береді; барлық әдеттегі циклдық құрылымдарды дұрыс генераторларды тиісті түрде қолдану арқылы ыңғайлы түрде модельдеуге болады. Мысалы, x = 1 - 10 аралығындағы циклді генератор арқылы итерация ретінде жүзеге асыруға болады, мысалы, Python-да for x in range(1, 10). Сонымен қатар, break генераторға finish жіберу арқылы және содан кейін циклде continue қолдану арқылы жүзеге асырылуы мүмкін.
Generators are usually invoked inside loops. The first time that a generator invocation is reached in a loop, an iterator object is created that encapsulates the state of the generator routine at its beginning, with arguments bound to the corresponding parameters. The generator's body is then executed in the context of that iterator until a special yield action is encountered; at that time, the value provided with the yield action is used as the value of the invocation expression. The next time the same generator invocation is reached in a subsequent iteration, the execution of the generator's body is resumed after the yield action, until yet another yield action is encountered. In addition to the yield action, execution of the generator body can also be terminated by a finish action, at which time the innermost loop enclosing the generator invocation is terminated. In more complicated situations, a generator may be used manually outside of a loop to create an iterator, which can then be used in various ways. Because generators compute their yielded values only on demand, they are useful for representing streams, such as sequences that would be expensive or impossible to compute at once. These include e. g. infinite sequences and live data streams. When eager evaluation is desirable (primarily when the sequence is finite, as otherwise evaluation will never terminate), one can either convert to a list, or use a parallel construction that creates a list instead of a generator. For example, in Python a generator g can be evaluated to a list l via l = list(g), while in F# the sequence expression seq { } evaluates lazily (a generator or sequence) but [ ] evaluates eagerly (a list). In the presence of generators, loop constructs of a language – such as for and while – can be reduced into a single loop end loop construct; all the usual loop constructs can then be comfortably simulated by using suitable generators in the right way. For example, a ranged loop like for x = 1 to 10 can be implemented as iteration through a generator, as in Python's for x in range(1, 10). Further, break can be implemented as sending finish to the generator and then using continue in the loop.
Уақыт шкаласы
Генераторлар алғаш рет CLU (1975 ж.) тілінде пайда болды, Icon (1977) жолдарды өңдеу тілінде маңызды рөл атқарды және қазір Python (2001), C#, Ruby, PHP, ECMAScript (ES6/ES2015 нұсқасынан бастап) және басқа да тілдерде қолжетімді. CLU және C# тілдерінде генераторлар итераторлар деп, ал Ruby тілінде – санаушылар деп аталады.
Generators first appeared in CLU (1975), were a prominent feature in the string manipulation language Icon (1977) and are now available in Python (2001), C#, Ruby, PHP, ECMAScript (as of ES6/ES2015), and other languages. In CLU and C#, generators are called iterators, and in Ruby, enumerators.
Лиспа
Common Lisp стандартының соңғы нұсқасында генераторлар болмайды, алайда CLtL2 немесе pygen-де құжатталған SERIES сияқты әртүрлі кітапханалық жүзеге асырулар бар.
The final Common Lisp standard does not natively provide generators, yet various library implementations exist, such as SERIES documented in CLtL2 or pygen.
С
C тілінде генератор функциялары тілдік құрылым ретінде жоқ, бірақ олар корутиналардың кіші жиыны болғандықтан, libdill сияқты стекпен жұмыс жасайтын корутиналарды іске асыратын кез келген фреймворк арқылы оларды іске асыру оңай. POSIX платформаларында, әр итерация бойынша контекст ауыстыру құны маңызды болмағанда немесе тек бір мезгілдестік емес, толық параллелизм қажет болғанда, pthreads және құбырларды пайдаланып өте қарапайым генератор функциясы фреймворкін құруға болады.
C does not have generator functions as a language construct, but, as they are a subset of coroutines, it is simple to implement them using any framework that implements stackful coroutines, such as libdill. On POSIX platforms, when the cost of context switching per iteration is not a concern, or full parallelism rather than merely concurrency is desired, a very simple generator function framework can be implemented using pthreads and pipes.
Python-тың атауы
2001 жылы 2.2 нұсқасында Python-ға генераторлар қосылды.
Generators were added to Python in version 2.2 in 2001.