Site Loader

Содержание

Введение в генераторы Python — Еще один блог веб разработчика

Оглавление

Генераторы – это функции, которые можно приостанавливать и возобновлять во время их выполнения, при этом они возвращают объект, который можно итерировать. В отличие от списков, они ленивы и поэтому работают с текущим элемент только по запросу. Таким образом, они намного эффективнее используют память при работе с большими наборами данных. В этой статье подробно описывается, как создавать функции генератор и выражения генератор, а также рассматривается пример их использования.

Функции генератора

Чтобы создать генератор, необходимо определить функцию, как обычно, но использовать yield вместо return, указывая интерпретатору, что эту функцию следует рассматривать как итератор:

def countdown(num):
    print('Starting')
    while num > 0:
        yield num
        num -= 1

Оператор yield приостанавливает функцию и сохраняет локальное состояние, чтобы его можно было возобновить с того места, где оно было остановлено.

Что происходит, когда вы вызываете эту функцию?

>>> def countdown(num):
...     print('Starting')
...     while num > 0:
...         yield num
...         num -= 1
...
>>> val = countdown(5)
>>> val
<generator object countdown at 0x10213aee8>

Вызов функции не выполняет ее. Мы знаем это, потому что строка Starting не печатается. Вместо этого функция возвращает объект-генератор, который используется для управления выполнением.

Объекты генератора выполняются при вызове next():

>>> next(val)
Starting
5

При первом вызове next() выполнение начинается с начала тела функции и продолжается до следующего оператора yield, где возвращается значение справа от оператора, последующие вызовы

next() продолжаются с оператора yield до конец функции, затем новый обход цикла и продолжение с начала тела функции, пока не будет вызван другой выход. Если yield не вызывается (что в нашем случае означает, что условие while не отрабатывается, потому что num <= 0), возникает исключение StopIteration:

>>> next(val)
4
>>> next(val)
3
>>> next(val)
2
>>> next(val)
1
>>> next(val)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Выражения-генератор (Generator Expressions)

Как и списки, генераторы также могут быть написаны таким же образом, за исключением того, что они возвращают объект генератора, а не список:

>>> my_list = ['a', 'b', 'c', 'd']
>>> gen_obj = (x for x in my_list)
>>> for val in gen_obj:
...     print(val)
...
a
b
c
d

Обратите внимание на круглые скобки по обеим сторонам второй строки, обозначающие выражение генератора, которое, по большей части, делает то же самое, что и генератор списка, но делает это лениво (то есть в момент запроса объекта):

>>> import sys
>>> g = (i * 2 for i in range(10000) if i % 3 == 0 or i % 5 == 0)
>>> print(sys.getsizeof(g))
72
>>> l = [i * 2 for i in range(10000) if i % 3 == 0 or i % 5 == 0]
>>> print(sys.getsizeof(l))
38216

Будьте внимательны, чтобы не перепутать синтаксис генератор списка с выражением генератора –

[] vs () – поскольку выражения генератора могут работать медленнее, чем генератор списка (при не хватки памяти):

>>> import cProfile
>>> cProfile.run('sum((i * 2 for i in range(10000000) if i % 3 == 0 or i % 5 == 0))')
         4666672 function calls in 3.531 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  4666668    2.936    0.000    2.936    0.000 <string>:1(<genexpr>)
        1    0.001    0.001    3.529    3.529 <string>:1(<module>)
        1    0.002    0.002    3.531    3.531 {built-in method exec}
        1    0.592    0.592    3.528    3.528 {built-in method sum}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


>>> cProfile.run('sum([i * 2 for i in range(10000000) if i % 3 == 0 or i % 5 == 0])')
         5 function calls in 3.054 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    2.725    2.725    2.725    2.725 <string>:1(<listcomp>)
        1    0.078    0.078    3.054    3.054 <string>:1(<module>)
        1    0.000    0.000    3.054    3.054 {built-in method exec}
        1    0.251    0.251    0.251    0.251 {built-in method sum}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

Это особенно заметно в приведенном выше примере.

ПРИМЕЧАНИЕ. Имейте в виду, что выражения генератора значительно быстрее, когда размер ваших данных превышает доступную память.

Случаи применения

Генераторы идеально подходят для чтения большого количества больших файлов, поскольку они выдают данные по одному фрагменту за раз, независимо от размера входного потока. Они также могут привести к более чистому коду путем разделения процесса итерации на более мелкие компоненты.

Пример 1

def emit_lines(pattern=None):
    lines = []
    for dir_path, dir_names, file_names in os.walk('test/'):
        for file_name in file_names:
            if file_name.endswith('.py'):
                for line in open(os.path.join(dir_path, file_name)):
                    if pattern in line:
                        lines.append(line)
    return lines

Эта функция просматривает набор файлов в указанном каталоге. Она открывает каждый файл и затем просматривает каждую строку, чтобы проверить соответствие шаблону.

Это прекрасно работает с небольшим количеством небольших файлов. Но что, если мы имеем дело с очень большими файлами? А что, если их много? К счастью, функция Python open() достаточно эффективна и не загружает весь файл в память. Но что, если наш список совпадений намного превышает доступную память на нашей машине?

Таким образом, вместо обработки нехватки места (при больших списках) и времени (почти бесконечный объем потока данных) при обработке больших объемов данных генераторы являются идеальным решением для использования, поскольку они выдают данные по одному за раз (вместо создание промежуточных списков).

Давайте посмотрим на версию вышеупомянутой проблемы для генератора и попытаемся понять, почему генераторы подходят для таких случаев использования с использованием конвейеров обработки.

Мы разделили весь наш процесс на три разных компонента:

  • Генерация множества имен файлов
  • Генерация всех строк из всех файлов
  • Фильтрация строк на основе сопоставления с образцом
def generate_filenames():
    """
    generates a sequence of opened files
    matching a specific extension
    """
    for dir_path, dir_names, file_names in os.walk('test/'):
        for file_name in file_names:
            if file_name.endswith('.py'):
                yield open(os.path.join(dir_path, file_name))

def cat_files(files):
    """
    takes in an iterable of filenames
    """
    for fname in files:
        for line in fname:
            yield line

def grep_files(lines, pattern=None):
    """
    takes in an iterable of lines
    """
    for line in lines:
        if pattern in line:
            yield line


py_files = generate_filenames()
py_file = cat_files(py_files)
lines = grep_files(py_file, 'python')
for line in lines:
    print (line)

В приведенном выше фрагменте мы не используем никаких дополнительных переменных для формирования списка строк, вместо этого мы создаем конвейер, который подает свои компоненты через процесс итерации по одному элементу за раз.

grep_files принимает объект-генератор всех строк файлов *.py. Точно так же cat_file вставляет в объект генератора все имена файлов в каталоге. Таким образом весь конвейер склеивается с помощью итераций.

Пример 2

Генераторы отлично работают и для рекурсивного парсинга веб-страниц:

import requests
import re


def get_pages(link):
    links_to_visit = []
    links_to_visit.append(link)
    while links_to_visit:
        current_link = links_to_visit.pop(0)
        page = requests.get(current_link)
        for url in re.findall('<a href="([^"]+)">', str(page.content)):
            if url[0] == '/':
                url = current_link + url[1:]
            pattern = re.compile('https?')
            if pattern.match(url):
                links_to_visit.append(url)
        yield current_link


webpage = get_pages('http://sample.com')
for result in webpage:
    print(result)

Здесь мы просто выбираем по одной странице за раз, а затем выполняем какое-то действие на странице. Как бы это выглядело без генератора? Либо выборка и обработка должны происходить в одной и той же функции (что приводит к высокосвязанному коду, который трудно протестировать), либо нам нужно получить все ссылки перед обработкой одной страницы.

Заключение

Генераторы позволяют нам запрашивать значения по мере необходимости, делая наши приложения более эффективными в использовании памяти и идеально подходящими для бесконечных потоков данных. Они также могут быть использованы для рефакторинга обработки из циклов, что приводит к более чистому, разъединенному коду. Если вы хотите увидеть больше примеров, ознакомьтесь с Generator Tricks for Systems Programmers и Iterator Chains as Pythonic Data Processing Pipelines.

Оригинальная статья:  Real Python  Introduction to Python Generators

Была ли вам полезна эта статья?

[5 / 4]

Генератор функций | Описание, настройка, характеристики

Что такое генератор функций и чем он отличается от генератора частоты? Давайте как раз об этом и поговорим в нашей статье.

Что такое генератор функций

Не так давно на моем столе появился этот чудо-прибор. Сочетание дизайна и удобства использования очень даже ничего.

Итак, теперь давайте обо всем по порядку, что представляет из себя эта белая коробочка с кнопочками и с небольшим табло? Написано на ней “Function Generator”, то есть, в переводе с англ. “генератор функций”.

Что такое генератор функций? Это по сути источник периодических сигналов и не только, которые могут принимать любую форму и частоту, которую вы им зададите (в пределах рабочего диапазона прибора).

Знаете сколько тысяч баксов стоит такой фаршированный приборчик?)) Поэтому, это название слишком громкое для нашего героя. На самом же деле он представляет из себя просто крутой генератор частоты. Ну раз уж написано на нем, что он генератор функций, пусть так оно и будет.

Виды сигналов

Для простых обывателей и любителей пожарить канифоль, типа меня и вас, реальный генератор функций за +100500 баксов будет нецелесообразным приобретением, а на практике для нас бывает достаточно трех видов сигналов:

это синусоидальный

треугольный

и прямоугольный сигнал

Их более чем достаточно на все случаи жизни. В народе их называют синус, треугольник и прямоугольник, которые без проблем может выдать наш герой.

Как формировать сигналы

Для того, чтобы задать амплитуду сигнала, мы крутим крутилку “AMPLITUDE”. Здесь под этим словом понимается двойная амплитуда или как его еще называют “размах сигнала” или “амплитуда от пика до пика”.

Давайте зададим сигнал размахом в 10 В и частотой в 2 МГц. Для наблюдения сигнала нам понадобится осциллограф. Так как у меня есть цифровой осциллограф OWON SDS6062, поэтому я буду делать скрины с помощью него:

Итак, что имеем на генераторе:

Что имеем на осциллографе:

синусоиадльный сигнал на осциллографе

Ништяк)

Меняем форму сигнала на пилу:

треугольный сигнал

Нормальная пила.

Смотрим прямоугольный сигнал:

Генератор функций

Очень даже ничего 😉

Описание разъемов и кнопок

На панели такого прибора можно увидеть три заветные кнопочки переключения сигналов:

Слева на генераторе можно увидеть вот такие кнопки

Под внешним счетчиком здесь имеется ввиду какой-либо периодический сигнал с какого-нибудь генератора частоты либо схемы. Подавая такой сигнал на разъем нашего генератора функций, мы с легкостью можем определить частоту неизвестного сигнала вплоть до 10 Мегагерц. То есть в данном случае генератор функций выполняет роль частотомера.

Как вы уже заметили, на лицевой панели также имеются еще три разъема, кроме  разъема для счета импульсов:

VCF – Voltage Controlled Frequency. По нашему ГУН. Расшифровывается как Генератор Управляемый Напряжением. Само название говорит о том, что мы можем менять частоту сигнала с генератора функций, подавая на этот разъем какое-либо напряжение. В зависимости от того, какое напряжение мы подаем, такая и будет частота 😉 Например, подавая переменное напряжение на такой разъем, мы можем на выходе генератора функций получить  сигнал с переменной частотой.

TTL OUT.  ТТЛ – Транзисторно-Транзисторная-Логика. OUT – выход. Этот выход предназначен для тактирования логических микросхем, построенных на так называемой транзисторно-транзисторной логике. То есть это логические элементы, которые в своем составе имеют только биполярные транзисторы и резисторы. Такие микросхемы делают в основном на питание +5 В.

Логический ноль – это уровень напряжения от 0 и до +0,5 В. Уровень логической единички от 2,4 и до +5 В. Поэтому, с этого выхода мы получаем прямоугольный периодический сигнал с чередующимися нулями и единицами: 0101010101… Частоту такого сигнала выставляем с помощью крутилки и кнопок выбора диапазона.

OUTPUT. Выход с генератора. Именно с этого разъема мы и получаем необходимый нам сигнал с генератора функций.

Также небольшой интерес представляют из себя эти две кнопочки:

Написано “attention”, что значит “внимание”. На самом деле там должно быть написано “attenuator”. Аттенюатор – слово не наше, означает как “ослабить, смягчить”. Видать, китайцы сэкономили на переводчике с китайского на английский, так как и “Амплитуда” на генераторе тоже написана с косяками ))

Итак, что за кнопочки -20dB и -40dB? dB – это децибелы (как-нибудь надо накарябать про них статью). А пока вот вам ссылочка на онлайн-калькулятор. Я за вас уже все посчитал. -20dB это значит, что мы можем ослабить выдаваемый генератором сигнал в 10 раз. -40dB – в 100 раз. А если нажмем сразу на 2 кнопочки разом, то у нас в сумме получится -60dB. Следовательно, мы можем ослабить сигнал в 1000 раз.

Повыше также еще есть кнопочка -10dB, которая ослабляет сигнал в 3 раза с копейками.

И остались у нас на разборе еще пара крутилок с кнопками

Кнопочки под ними задействуют соответствующую крутилку при нажатии.

R/PRump/Pulse – Уклон/Импульс.

С помощью этой крутилки мы можем чуток поиграться с формой сигнала, задавая уклон. Вот некоторые осциллограммы синусоиды и пилы, которые я немного видоизменил с помощью этой крутилки:

Крайнее левое положение крутилки

Генератор функций

Крайнее правое положение крутилки

Генератор функций

Крутнул чуть-чуть:

Генератор функций

Крайнее левое положение крутилки

Генератор функций

Крайнее правое положение крутилки

Генератор функций

Крутанул чуток:

Генератор функций

У прямоугольного сигнала с помощью этой крутилки мы можем менять ширину импульсов, тем самым меняя скважность сигнала, а следовательно и коэффициент заполнения.

Генератор функций

Крайнее левое положение крутилки

Генератор функций

Крайнее правое.

Генератор функций

Крутилка DC LEVEL. Direct Current Level. В переводе с англ. уровень постоянного тока. С помощью этой крутилки мы можем добавлять в сигнал постоянную составляющую, то есть добавлять постоянное напряжение или как говорится, “поднять или опустить сигнал над уровнем моря”. В данном случае на уровнем земли. А как вы помните, земля у нас с потенциалом 0 В.

Если показать рисунком, то получается вот так:

В первом случае мы к синусоиде прибавляем положительное напряжение, а во втором случае – отрицательное.

Давайте смешаем синусоиду с постоянным напряжением, добавляя или убавляя его с помощью крутилки DC LEVEL:

Прибавил постоянное напряжение к синусоидальному сигналу:

Генератор функций

А здесь я смешал синусоиду с отрицательным постоянным напряжением:

Генератор функций

В этих случая главное не забыть поставить в настройках осциллографа “измерение постоянного тока”, иначе у вас сигнал не сдвинется.

При желании можно также тактировать МК, задав 5 В и добавив постоянного напряжения с помощью крутилки DC, хотя, как я уже писал, можно подцепить МК  к выходу “TTL OUT” генератора функций.

выход TTL генератор функций

Генератор функций в роли частотомера

Давайте проверим, как он считает частоту. Подаю на него частоту в 15 Килогерц с другого китайского генератора. Смотрим, что насчитал наш генератор функций (на показания справа не обращайте внимание):

Ровно 15 КГц.

Характеристика генератора функций

Мой генератор выдает максимум частоты в 2,49 МГц и размах напряжения в 22,2 В. В принципе, для меня этого вполне будет достаточно, как для начинающего электронщика. Вот к нему инструкция на русском. Также прилагаю скриншот его характеристик:

генератор функций характеристика

Заключение

Как я уже сказал, взял я его на Алике в день распродажи 11 ноября и он мне обошелся в 8700 деревянных, при цене типа в 9600, но по крайней мере дешевле не нашел. Глянуть на Алике этот прибор и сравнить цены вы можете по этой ссылке. 

Где можно применить этот прибор?  В основном везде, где надо подать тестовый сигнал и посмотреть, что получится на выходе. Это усилительная аудиотехника, различные фильтры, резонансные контура и тд.

А вот также видеоролик этого генератора от ЧипаДипа

Функциональный генератор

Функциональный генератор назван так не потому, что он хорошо выполняет свою функцию (хотя если он собран качественно, так оно и будет), а потому, что он генерирует сигналы, соответствующие по форме графикам различным математическим функций. Например: прямоугольные, треугольные, синусоидальные. Предлагаемый вариант такого генератора, который придумал автор Instructables под ником The_Technocrat, работает в звуковом и ультразвуковом диапазонах. Он облегчает проверку и настройку звуковых усилителей, устройств на логических микросхемах, драйверов двигателей, преобразователей напряжения и многого другого. Самый быстрый и проверенный способ построить функциональный генератор — применить в нём специализированную микросхему, в данном случае типа IC8038:

Диапазон частот генератора разбит на четыре поддиапазона, смена которых производится переключением конденсаторов. На трёх выходах микросхема с обвязкой вырабатывает сразу три сигнала различных форм, каждый из которых можно подать на расположенный на той же плате усилитель (LF351N). Четвёртый режим соответствует пропусканию прямоугольных импульсов через диод, чтобы проходила только одна полуволна — полезно при проверке устройств с цифровыми микросхемами.


Выбранные разработчиком DIP-переключатели для поставленной цели неоптимальны: если случайно выбрать более одного выхода, они окажутся замкнуты друг на друга, а соединять между собой выходы, уровни на которых отличаются, нельзя. Это может вызвать перегрев микросхемы. Лучше взять галетные переключатели.

Переменные резисторы служат для плавных регулировок: R1 — частоты, R2 — скважности прямоугольных импульсов (при генерации сигналов других форм его надо устанавливать в среднее положение), R5 — амплитуды. Подстроечные резисторы R3 и R4 позволяют уменьшить искажения для минимума при генерации синусоиды.

Работу над генератором мастер начинает с составления чертежа печатный платы. Получилось вот что:

Но по одной такой картинке плату не изготовить (она нужна, скорее, для справки по размещению компонентов, если вы заказали плату без шелкографии), поэтому для желающих повторить конструкцию The_Technocrat выложил Gerber-файлы. Можно также изготовить печатную плату самостоятельно ЛУТом или собрать генератор на макетной плате. Всё зависит от ваших возможностей и предпочтений. Разработчик получил вот что:

На плату мастер устанавливает все детали согласно подсказке на шелкографии или картинке выше. Микросхемы, во избежание их перегрева, лучше устанавливать после остальных компонентов. После этого на выход устройства он подключает осциллограф, а на вход — двуполярный 12-вольтовый источник питания. Выбрав какую-нибудь частоту или амплитуду, он первым делом выбирает режим генерации синусоиды, чтобы настроить подстроечные резисторы и больше их не трогать. Выставляет регулятор скважности в промежуточное положение, но несмотря на это, на экране — не совсем синусоида:

При помощи уже упомянутых резисторов R3 и R4 он добивается от синусоиды правильной формы. Результат не показывает, но я ему почему-то верю. На очереди — меандр:

Мастер вращает ось резистора R2 и получает вместо меандра прямоугольные импульсы различной скважности:

Осталось проверить режим генерации треугольных импульсов:

Внимание: на транзисторы, работающие в ключевом режиме и не имеющие теплоотводов, нельзя подавать с генератора управляющие сигналы никаких других форм, кроме прямоугольной. Скважность при этом можно менять и получать ШИМ.


Убедившись, что генератор работает, The_Technocrat изготавливает для него отдельный двуполярный стабилизированный БП (схему приводить нет смысла, там 7812 и 7912 и всё до боли стандартно):

С обратной стороны:

Затем берёт кусок оргстекла и устанавливает на него платы БП и генератора, чтобы они всегда были вместе, как попугаи-неразлучники:

Если устройство не работает, мастер советует проверить, какая часть виновата: генератор или усилитель. Сам он предпочитает проверять в направлении от выхода: смотрим, есть ли сигнал на выходе усилителя, если нет, перемещается к выходу генератора, или к входу усилителя, что одно и то же. Нет сигнала и там — не работает генератор. Есть — проблема в усилителе. Возможна проверка и в обратном направлении: осциллограф или наушники оставляем на выходе, а точки соединения выхода генератора с входом усилителя касаемся, чтобы получить наводку. Если до этого была тишина, а теперь появился фон, дело в генераторе. Ничего не изменилось — в усилителе. Обоими способами можно также проверить точки соединения в цепочке генератор-переключатель-резистор-усилитель. Неисправность локализована, и понятно, правильность сборки какого узла (и исправность какой микросхемы) надо проверять.


Источник Доставка новых самоделок на почту

Получайте на почту подборку новых самоделок. Никакого спама, только полезные идеи!

*Заполняя форму вы соглашаетесь на обработку персональных данных

Становитесь автором сайта, публикуйте собственные статьи, описания самоделок с оплатой за текст. Подробнее здесь.

Про Python — Справочник — Generator (генератор)

Функция, возвращающая подвид итератора, генерирующий значения.

Словом «генератор» обычно обозначается функция-генератор (или метод-генератор), возвращающая итератор генератора. Однако иногда слово может быть использовано и для обозначения самого итератора. В случаях, когда контекст непонятен лучше использовать полные термины: функция-генератор и итератор генератора. Итератор генератора — это объект, порождаемый функцией-генератором.
Генераторы являются простым средством для создания итераторов. Всё, что можно сделать при помощи генераторов можно также сделать при помощи итераторов, построенных на классах. Но в случае генераторов методы __iter__() и __next__() создаются автоматически, также автоматически возбуждается StopIteration, да и поддерживать генераторы проще и удобнее, чем реализовывать то же с использованием классов.
Выглядят функции-генераторы также как и обычные, но содержат выражения с ключевым словом yield для последовательного генерирования значений, которые могут быть использованы в циклах for in, либо их получения при помощи функции next().

На каждой yield работа функции временно приостанавливается, при этом сохраняется состояние исполнения, включая локальные переменные, указатель на текущую инструкцию, внутренний стек и состояние обработки исключения. При последующем обращении к итератору генератора (при вызовах его методов) функция продолжает своё исполнение с места, на котором была приостановлена. Этим функции-генераторы отличаются от обычных функций, при вызове которых исполнение всякий раз начинается с начала.

Если функция достигает инструкции return, либо конца (без указания упомянутой инструкции), возбуждается исключение StopIteration и итератор исчерпывает себя.

    def my_animal_generator():

yield 'корова'

for animal in ['кот', 'собака', 'медведь']:
yield animal

yield 'кит'

for animal in my_animal_generator():
print(animal)
# корова кот собака медведь кит


Функции-генераторы весьма похожи на сопрограммы: могут выдывать значения несколько раз, имеют более одной точки входа, их выполнение может быть приостановлено. Единственным различием является то, что функции-генераторы не могут определять то, как должно продолжаться исполнение (что должно происходить) после выдачи значения — управление всегда передаётся коду, вызвавшему генератор.


Инструкция yield может употребляться и в конструкции try except. Если к генератору не обратились до его финализации (финализация происходит, когда счётчик ссылок доходит до нуля, либо когда происходит сборка мусора), будет вызван метод итератора .close(), что позволяет выполнить оставшиеся в блоке finally инструкции.

В версии +py2.2, была возможность использовать генераторы при помощи импорта from __future__ import generators.

Синонимы поиска: Generator (генератор), yield, yeild, генераторы

Генератор функций — Function generator

Простой аналоговый функциональный генератор, около 1990 DDS генератор функций

Функциональный генератор , как правило , часть электронного измерительного оборудования или программного обеспечения , используемое для генерирования различных типов электрических сигналов в широком диапазоне частот. Некоторые из наиболее распространенных форм сигналов , производимых генератором функции являются синусоида, меандр, треугольной формы волны и пилообразной формы. Эти сигналы могут быть либо повторяющимися или однократный (который требует внутреннего или внешнего источника запуска). Интегральные схемы , используемые для генерации формы сигнала могут также быть описаны как ИС функционального генератора.

В дополнении к производству синусоидальных волн, функциональные генераторы обычно могут производить другие повторяющиеся сигналы, включая пилообразные и треугольные сигналы, квадратные волны, и импульсы. Еще одна функция, включенная на многих генераторов функций является возможность добавления постоянного тока смещения.

Хотя функциональные генераторы охватывают как аудио и ВЧ частот, они, как правило , не подходит для приложений, требующих низкое искажение или стабильные сигналы частоты. Когда эти черты необходимы, другие генераторы сигналов будут более подходящими.

Некоторые функциональные генераторы могут быть фазовой автоподстройки с внешним источником сигнала (который может быть опорной частоты) или другого функционального генератора.

Функциональные генераторы используются в разработке, испытании и ремонте электронного оборудования. Например, они могут быть использованы в качестве источника сигнала для тестирования усилителей или ввести сигнал ошибки в контур управления. Функциональные генераторы в основном используется для работы с аналоговыми схемами , связанные импульсные генераторы в основном используются для работы с цифровыми схемами .

Электронные инструменты

За работой

Простые функциональные генераторы обычно генерируют треугольную форму волны, частота которого может регулироваться плавно, а также на этапах. Эта треугольная волна используются в качестве основы для всех других своих выходов. Треугольная волна генерируются многократно зарядка и разрядки конденсатора от постоянного источника тока . Это приводит к линейно восходящему и нисходящему линейному изменению напряжения. Поскольку выходное напряжение достигает верхний или нижний предел, зарядка или разрядка восстанавливается с использованием компаратора , производя линейную треугольную волну. Путем изменения тока и размера конденсатора, различные частоты могут быть получены. Sawtooth волны могут быть получены путем медленного заряда конденсатора, используя ток, но с использованием диода через источник тока для разряда быстро — полярность диода изменяет полярность результирующего пилообразной, т.е. медленный рост и быстрое падение, или быстрый рост и медленное падение.

50% рабочий цикл квадратные волны легко получить, заметив ли конденсатор заряжается или разряжается, что находит отражение в выходной ток коммутации компаратора. Другие рабочие циклы (теоретически от 0% до 100%) может быть получено с использованием компаратора и пилообразной или треугольник сигнала. Большинство функциональных генераторов также содержать нелинейный диод формирования контура , который может преобразовывать треугольную волну в достаточно точную синусоиду путем округления углов треугольной волны в процессе , подобном отсечение в аудиосистемах.

Типичный функциональный генератор может обеспечить частоты до 20 МГц. RF генераторы для более высоких частот не функционируют генераторы в строгом смысле этого слова, так как они обычно производят только чистые или модулированные синусоидальные сигналы.

Функциональные генераторы, как и большинство генераторов сигналов , также может содержать аттенюатор , различные способы модулирования выходного сигнала, и часто возможность автоматически и повторно «развертка» частота выходного сигнала (с помощью управляемого напряжения генератора ) между два оператора определенного ограничения. Эта способность делает его очень легко оценить частотную характеристику данной электронной схемы .

Некоторые функциональные генераторы могут также генерировать белый или розовый шум .

Более продвинутые функциональные генераторы называются Генераторы сигналов произвольной формы (AWG). Они используют прямые цифровой синтез методов (DDS) , чтобы генерировать любой сигнал , который может быть описан с помощью таблицы амплитуд.

Характеристики

Типичные характеристики для функционального генератора общего назначения являются:

  • Производит синусоидальный, квадратной, треугольной, пилообразной (рампы), и импульсный выход. Генераторы сигналов произвольной формы может производить волны любой формы.
  • Он может генерировать широкий диапазон частот. Например, Tektronix FG 502 (около 1974) охватывает 0,1 Гц до 11 МГц.
  • Стабильность частоты 0,1 процента в час для аналоговых генераторов или 500 частей на миллион для цифрового генератора.
  • Максимальное синусоида искажение около 1% (точности диода формирующей сети) для аналоговых генераторов. Генераторы сигналов произвольной формы может иметь искажения меньше чем -55 дБ ниже 50 кГц и менее чем -40 дБ выше 50 кГц.
  • Некоторые функциональные генераторы могут быть фазовой автоподстройки к внешнему источнику сигнала, который может быть опорной частоты или другой генератор функций.
  • Амплитудной модуляции (АМ), частотной модуляции (ЧМ) или фазовой модуляции (PM), может быть поддержано.
  • Амплитуда выходного сигнала до 10 В от пика до пика .
  • Амплитуда может быть изменена, как правило , с помощью калиброванного аттенюатора с шагом десятилетия и непрерывной регулировкой в течение каждого десятилетия.
  • Некоторые генераторы обеспечивают постоянное напряжение смещения, например, регулируемого между -5V до + 5V.
  • Выходной импеданс 50 Ом .

Программного обеспечения

Совершенно иной подход к генерации функции заключается в использовании программного обеспечения инструкции для генерации сигнала, с обеспечением выхода. Так , например, общее назначение цифровой компьютер может быть использован для генерирования сигнала; если диапазон частот и амплитуды являются приемлемыми, то звуковая карта установлена на большинстве компьютеров может быть использован для вывода генерируемой волны.

Печатные элементы

генератор сигналов

Элемент электронной схемы используется для генерации формы сигнала в пределах другого устройства , которое может быть использовано в области связи и измерительные цепях, а также в инструменте функционального генератора. Примерами являются Экзар XR2206 и в Intersil ICL8038 интегральные схемы , которые могут генерировать синус, квадрат, треугольник, рампы, и импульсные сигналы , при частоте напряжения-управляемой .

Генератор функций

Электронный элемент контура , который обеспечивает выходной сигнал , пропорциональный некоторой математической функции (такие , как квадратный корень) его вход; такие устройства используются в управлении с обратной связью систем и в аналоговых вычислительных машинах . Примеры являются Raytheon квадратичных трубок QK329 и вход усилителя Intersil ICL8048 / антилогарифма.

Механические генераторы функций

Механические функциональные генераторы являются связями , механизмы кулачкового следящими или некруглыми зубчатые колеса , предназначенные для воспроизведения различных типов функций, либо периодические (например , синусоидального или косинус) или однократный (логарифм, параболические, касательные функции и т.д.).

Измерительные приборы , такие как датчики давления, высотомер и барометр включают в себя генераторы функций связи типа в качестве средства линеаризации. До появления цифровых вычислительных машин, механические функции генераторы были использованы при строительстве систем управления огнем и механических калькуляторов .

  • Четыре-бар функции генератора функции Log (и) в течение 1 <и <10.

  • Кулисный-слайдер функции генератора функции Log (и) в течение 1 <и <10.

  • Ползунок-кулисный функциональный генератор функции Tan (и) при 0 <и <45 °.

Смотрите также

Рекомендации

внешняя ссылка

Все о выражениях-генераторах, генераторах списков, множеств и словарей / Habr

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

Эта статья глубже и детальней предыдущих и поэтому может быть интересна не только новичкам, но и достаточно опытным Python-разработчикам.

Будут рассмотрены: выражения-генераторы, генераторы списка, словаря и множества, вложенные генераторы (5 вариантов), работа с enumerate(), range().
А также: классификация и терминология, синтаксис, аналоги в виде циклов и примеры применения.

Я постарался рассмотреть тонкости и нюансы, которые освещаются далеко не во всех книгах и курсах, и, в том числе, отсутствуют в уже опубликованных на Habrahabr статьях на эту тему.

Оглавление:


1. Определения и классификация.
2. Синтаксис.
3. Аналоги в виде цикла for и в виде функций.
4. Выражения-генераторы.
5. Генерация стандартных коллекций.
6. Периодичность и частичный перебор.
7. Вложенные циклы и генераторы.
8. Использование range().
9. Приложение 1. Дополнительные примеры.
10. Приложение 2. Ссылки по теме.

1. Определения и классификация


1.1 Что и зачем

  • Генераторы выражений предназначены для компактного и удобного способа генерации коллекций элементов, а также преобразования одного типа коллекций в другой.
  • В процессе генерации или преобразования возможно применение условий и модификация элементов.
  • Генераторы выражений являются синтаксическим сахаром и не решают задач, которые нельзя было бы решить без их использования.

1.2 Преимущества использования генераторов выражений

  • Более короткий и удобный синтаксис, чем генерация в обычном цикле.
  • Более понятный и читаемый синтаксис чем функциональный аналог сочетающий одновременное применение функций map(), filter() и lambda.
  • В целом: быстрее набирать, легче читать, особенно когда подобных операций много в коде.

1.3 Классификация и особенности

Сразу скажу, что существует некоторая терминологическая путаница в русских названиях того, о чем мы будем говорить.

В данной статье используются следующие обозначения:

  • выражение-генератор (generator expression) — выражение в круглых скобках которое выдает создает на каждой итерации новый элемент по правилам.
  • генератор коллекции — обобщенное название для генератора списка (list comprehension), генератора словаря (dictionary comprehension) и генератора множества (set comprehension).


В отдельных местах, чтобы избежать нагромождения терминов, будет использоваться термин «генератор» без дополнительных уточнений.

2. Синтаксис


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

Общие принципы важные для понимания:

  • Ввод — это итератор — это может быть функция-генератор, выражение-генератор, коллекция — любой объект поддерживающий итерацию по нему.
  • Условие — это фильтр при выполнении которого элемент пойдет в финальное выражение, если элемент ему не удовлетворяет, он будет пропущен.
  • Финальное выражение — преобразование каждого выбранного элемента перед его выводом или просто вывод без изменений.

2.1 Базовый синтаксис

list_a = [-2, -1, 0, 1, 2, 3, 4, 5]    # Пусть у нас есть исходный список
list_b = [x for x in list_a]           # Создадим новый список используя генератор списка
print(list_b)                          # [-2, -1, 0, 1, 2, 3, 4, 5]
print(list_a is list_b)                # False - это разные объекты!

По сути, ничего интересного тут не произошло, мы просто получили копию списка. Делать такие копии или просто перегонять коллекции из типа в тип с помощью генераторов особого смысла нет — это можно сделать значительно проще применив соответствующие методы или функции создания коллекций (рассматривались в первой статье цикла).

Мощь генераторов выражений заключается в том, что мы можем задавать условия для включения элемента в новую коллекцию и можем делать преобразование текущего элемента с помощью выражения или функции перед его выводом (включением в новую коллекцию).

2.2 Добавляем условие для фильтрации


Важно: Условие проверяется на каждой итерации, и только элементы ему удовлетворяющие идут в обработку в выражении.

Добавим в предыдущий пример условие — брать только четные элементы.

# if x % 2 == 0 - остаток от деления на 2 равен нулю - число четное
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] 
list_b = [x for x in list_a if x % 2 == 0]
print(list_b)   # [-2, 0, 2, 4]

Мы можем использовать несколько условий, комбинируя их логическими операторами:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x for x in list_a if x % 2 == 0 and x > 0]
# берем те x, которые одновременно четные и больше нуля
print(list_b)   # [2, 4]

2.3 Добавляем обработку элемента в выражении


Мы можем вставлять не сам текущий элемент, прошедший фильтр, а результат вычисления выражения с ним или результат его обработки функцией.

Важно: Выражение выполняется независимо на каждой итерации, обрабатывая каждый элемент индивидуально.

Например, можем посчитать квадраты значений каждого элемента:

list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x**2 for x in list_a]
print(list_b)   # [4, 1, 0, 1, 4, 9, 16, 25]

Или посчитать длины строк c помощью функции len()
list_a = ['a', 'abc', 'abcde']
list_b = [len(x) for x in list_a]
print(list_b)   # [1, 3, 5]

2.4 Ветвление выражения


Обратите внимание: Мы можем использовать (начиная с Python 2.5) в выражении конструкцию if-else для ветвления финального выражения.

В таком случае:

  • Условия ветвления пишутся не после, а перед итератором.
  • В данном случае if-else это не фильтр перед выполнением выражения, а ветвление самого выражения, то есть переменная уже прошла фильтр, но в зависимости от условия может быть обработана по-разному!
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x if x < 0 else x**2 for x in list_a]
# Если x-отрицательное - берем x, в остальных случаях - берем квадрат x
print(list_b)   # [-2, -1, 0, 1, 4, 9, 16, 25]

Никто не запрещает комбинировать фильтрацию и ветвление:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x**3 if x < 0 else x**2 for x in list_a if x % 2 == 0]
# вначале фильтр пропускает в выражение только четные значения
# после этого ветвление в выражении для отрицательных возводит в куб, а для остальных в квадрат
print(list_b)   # [-8, 0, 4, 16]

Этот же пример в виде цикла
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = []
for x in list_a:
    if x % 2 == 0:
        if x < 0:
            list_b.append(x ** 3)
        else:
            list_b.append(x ** 2)
print(list_b)   # [-8, 0, 4, 16]

2.5 Улучшаем читаемость


Не забываем, что в Python синтаксис позволяет использовать переносы строк внутри скобок. Используя эту возможность, можно сделать синтаксис генераторов выражений более легким для чтения:
numbers = range(10)

# Before
squared_evens = [n ** 2 for n in numbers if n % 2 == 0]

# After
squared_evens = [
    n ** 2
    for n in numbers
    if n % 2 == 0
]

3. Аналоги в виде цикла for и в виде функций


Как уже говорилось выше, задачи решаемые с помощью генераторов выражений можно решить и без них. Приведем другие подходы, которые могут быть использованы для решения тех же задач.

Для примера возьмем простую задачу — сделаем из списка чисел список квадратов четных чисел и решим ее с помощью трех разных подходов:

3.1 Решение с помощью генератора списка

numbers = range(10)
squared_evens = [n ** 2 for n in numbers if n % 2 == 0]
print(squared_evens)   # [0, 4, 16, 36, 64]

3.2. Решение c помощью цикла for


Важно: Каждый генератор выражений можно переписать в виде цикла for, но не каждый цикл for можно представить в виде такого выражения.
numbers = range(10)
squared_evens = []
for n in numbers:
    if n % 2 == 0:
        squared_evens.append(n ** 2)
print(squared_evens)   # [0, 4, 16, 36, 64]

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

3.3. Решение с помощью функций.


Для начала, замечу, что выражение генераторы и генераторы коллекций — это тоже функциональный стиль, но более новый и предпочтительный.

Можно применять и более старые функциональные подходы для решения тех же задач, комбинируя map(), lambda и filter().

numbers = range(10)
squared_evens = map(lambda n: n ** 2, filter(lambda n: n % 2 == 0, numbers))
print(squared_evens)         # <map object at 0x7f661e5dba20>
print(list(squared_evens))   # [0, 4, 16, 36, 64]
# Примечание: в Python 2 в переменной squared_evens окажется сразу список, а в Python 3 «map object», который мы превращаем в список с помощью list()

Несмотря на то, что подобный пример вполне рабочий, читается он тяжело и использование синтаксиса генераторов выражений будет более предпочительным и понятным.

4. Выражения-генераторы


Выражения-генераторы (generator expressions) доступны, начиная с Python 2.4. Основное их отличие от генераторов коллекций в том, что они выдают элемент по-одному, не загружая в память сразу всю коллекцию.

UPD: Еще раз обратите внимание на этот момент: если мы создаем большую структуру данных без использования генератора, то она загружается в память целиком, соответственно, это увеличивает расход памяти Вашим приложением, а в крайних случаях памяти может просто не хватить и Ваше приложение «упадет» с MemoryError. В случае использования выражения-генератора, такого не происходит, так как элементы создаются по-одному, в момент обращения.

Пример выражения-генератора:

list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_gen = (i for i in list_a)    # выражение-генератор
print(next(my_gen))     # -2 - получаем очередной элемент генератора
print(next(my_gen))     # -1 - получаем очередной элемент генератора

Особенности выражений-генераторов


  1. Генаратор нельзя писать без скобок — это синтаксическая ошибка.
    # my_gen = i for i in list_a      # SyntaxError: invalid syntax

  2. При передаче в функцию дополнительные скобки необязательны
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    my_sum = sum(i for i in list_a)
    # my_sum = sum((i for i in list_a))  # так тоже можно
    print(my_sum)   # 12

  3. Нельзя получить длину функцией len()
    # my_len = len(i for i in list_a)  # TypeError: object of type 'generator' has no len()

  4. Нельзя распечатать элементы функцией print()
    print(my_gen)   # <generator object <genexpr> at 0x7f162db32af0>
    

  5. Обратите внимание, что после прохождения по выражению-генератору оно остается пустым!
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    my_gen = (i for i in list_a)
    print(sum(my_gen))  # 12
    print(sum(my_gen))  # 0

  6. Выражение-генератор может быть бесконечным.
    import itertools
    inf_gen = (x for x in itertools.count())  # бесконечный генератор от 0 to бесконечности!
    Будьте осторожны в работе с такими генераторами, так как при не правильном использовании «эффект» будет как от бесконечного цикла.
  7. К выражению-генератору не применимы срезы!
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    my_gen = (i for i in list_a)
    my_gen_sliced = my_gen[1:3]
    # TypeError: 'generator' object is not subscriptable

  8. Из генератора легко получать нужную коллекцию. Это подробно рассматривается в следующей главе.

5. Генерация стандартных коллекций


5.1 Создание коллекций из выражения-генератора


Создание коллекций из выражения-генератора с помощью функций list(), tuple(), set(), frozenset()

Примечание: Так можно создать и неизменное множество и кортеж, так как неизменными они станет уже после генерации.

Внимание: Для строки такой способ не работает! Синтаксис создания генератора словаря таким образом имеет свои особенности, он рассмотрен в следующем под-разделе.

  1. Передачей готового выражения-генератора присвоенного переменной в функцию создания коллекции.
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    my_gen = (i for i in list_a)   # выражение-генератор
    my_list = list(my_gen) 
    print(my_list)          # [-2, -1, 0, 1, 2, 3, 4, 5]

  2. Написание выражения-генератора сразу внутри скобок вызываемой функции создания коллекции.
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    my_list = list(i for i in list_a)
    print(my_list)          # [-2, -1, 0, 1, 2, 3, 4, 5]

    То же самое для кортежа, множества и неизменного множества
    # кортеж
    my_tuple = tuple(i for i in list_a)
    print(my_tuple)         # (-2, -1, 0, 1, 2, 3, 4, 5)
    
    # множество
    my_set = set(i for i in list_a)
    print(my_set)           # {0, 1, 2, 3, 4, 5, -1, -2}
    
    # неизменное множество
    my_frozenset = frozenset(i for i in list_a)
    print(my_frozenset)     # frozenset({0, 1, 2, 3, 4, 5, -1, -2})

5.2 Специальный синтаксис генераторов коллекций


В отличии от выражения-генератора, которое выдает значение по-одному, не загружая всю коллекцию в память, при использовании генераторов коллекций, коллекция генерируется сразу целиком.

Соответственно, вместо особенности выражений-генераторов перечисленных выше, такая коллекция будет обладать всеми стандартными свойствами характерными для коллекции данного типа.

Обратите внимание, что для генерации множества и словаря используются одинаковые скобки, разница в том, что у словаря указывается двойной элемент ключ: значение.

  1. Генератор списка (list comprehension)
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    my_list = [i for i in list_a]
    print(my_list)          # [-2, -1, 0, 1, 2, 3, 4, 5]

    Не пишите круглые скобки в квадратных!
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    my_list = [(i for i in list_a)]
    print(my_list)          # [<generator object <genexpr> at 0x7fb81103bf68>]

  2. Генератор множества (set comprehension)
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    my_set= {i for i in list_a}
    print(my_set)       # {0, 1, 2, 3, 4, 5, -1, -2} - порядок случаен

  3. Генератор словаря (dictionary comprehension)
    переворачивание словаря
    dict_abc = {'a': 1, 'b': 2, 'c': 3, 'd': 3}
    dict_123 = {v: k for k, v in dict_abc.items()}
    print(dict_123)  # {1: 'a', 2: 'b', 3: 'd'}
                     # Обратите внимание, мы потеряли "с"! Так как значения были одинаковы, 
                     # то когда они стали ключами, только последнее значение сохранилось.

    Словарь из списка:
    list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
    dict_a = {x: x**2 for x in list_a}
    print(dict_a)   # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, -2: 4, -1: 1, 5: 25}

    Важно! Такой синтаксис создания словаря работает только в фигурных скобках, выражение-генератор так создать нельзя, для этого используется немного другой синтаксис (благодарю longclaps за подсказку в комментариях):
    # dict_gen = (x: x**2 for x in list_a)      # SyntaxError: invalid syntax
    dict_gen = ((x, x ** 2) for x in list_a)    # Корректный вариант генератора-выражения для словаря
    # dict_a = dict(x: x**2 for x in list_a)    # SyntaxError: invalid syntax
    dict_a = dict((x, x ** 2) for x in list_a)  # Корректный вариант синтаксиса от @longclaps

5.3 Генерация строк


Для создания строки вместо синтаксиса выражений-генераторов используется метод строки .join(), которому в качестве аргументов можно передать выражение генератор.
Обратите внимание: элементы коллекции для объединения в строку должны быть строками!
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
# используем генератор прямо в .join() одновременно приводя элементы к строковому типу
my_str = ''.join(str(x) for x in list_a)
print(my_str)  # -2-1012345

6. Периодичность и частичный перебор


6.1 Работа с enumerate()


Иногда в условиях задачи в условии-фильтре нужна не проверка значения текущего элемента, а проверка на определенную периодичность, то есть, например, нужно брать каждый третий элемент.

Для подобных задач можно использовать функцию enumerate(), задающую счетчик при обходе итератора в цикле:

for i, x in enumerate(iterable)
здесь x — текущий элемент i — его порядковый номер, начиная с нуля

Проиллюстрируем работу с индексами:

list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_d = [(i, x) for i, x in enumerate(list_a)]
print(list_d)   # [(0, -2), (1, -1), (2, 0), (3, 1), (4, 2), (5, 3), (6, 4), (7, 5)]

Теперь попробуем решить реальную задачу — выберем в генераторе списка каждый третий элемент из исходного списка:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_e = [x for i, x in enumerate(list_a, 1) if i % 3 == 0]
print(list_e)   # [0, 3]

Важные особенности работы функции enumerate():

  1. Возможны два варианта вызова функции enumerate():
    • enumerate(iterator) без второго параметра считает с 0.
    • enumerate(iterator, start) — начинает считать с значения start. Удобно, например, если нам надо считать с 1, а не 0.

  2. enumerate() возвращает кортеж из порядкового номера и значения текущего элемента итератора. Кортеж в выражении-генераторе результате можно получить двумя способами:
    • (i, j) for i, j in enumerate(iterator) — скобки в первой паре нужны!
    • pair for pair in enumerate(mylist) — мы работаем сразу с парой

  3. Индексы считаются для всех обработанных элементов, без учета прошли они в дальнейшем условие или нет!
    first_ten_even = [(i, x) for i, x in enumerate(range(10)) if x % 2 == 0]
    print(first_ten_even)   # [(0, 0), (2, 2), (4, 4), (6, 6), (8, 8)]

  4. Функция enumerate() не обращается к каким-то внутренним атрибутам коллекции, а просто реализует счетчик обработанных элементов, поэтому ничего не мешает ее использовать для неупорядоченных коллекций не имеющих индексации.
  5. Если мы ограничиваем количество элементов включенных в результат по enumerate() счетчику (например if i < 10), то итератор будет все равно обработан целиком, что в случае огромной коллекции будет очень ресурс-затратно. Решение этой проблемы рассматривается ниже в под-разделе «Перебор части итерируемого».

6.2 Перебор части итерируемого.


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

Если мы используем обычное генераторное выражение с условием ограничением по enumerate() индексу или срез полученной результирующей коллекции, то нам в любом случае придется пройти всю огромную коллекцию и потратить на это уйму компьютерных ресурсов.

Выходом может быть использование функции islice() из пакета itertools.

import itertools
first_ten = (itertools.islice((x for x in range(1000000000) if x % 2 == 0), 10))
print(list(first_ten))  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Для сомневающихся: проверяем время выполнения
import time
import itertools

# На генераторе с малым количеством элементов
start_time = time.time()
first_ten = (itertools.islice((x for x in range(100) if x % 2 == 0), 10))
print(list(first_ten))  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
elapsed_time = time.time() - start_time
print(elapsed_time)  # 3.409385681152344e-05

# На генераторе с огромным количеством элементов
start_time = time.time()
first_ten = (itertools.islice((x for x in range(100000000) if x % 2 == 0), 10))
print(list(first_ten))  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
elapsed_time = time.time() - start_time
print(elapsed_time)  # 1.1205673217773438e-05

# То есть максимальное количество элементов в генераторе range() мы увеличили на 6 порядков, 
# а время исполнения осталось того же порядка

7. Вложенные циклы и генераторы


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

7.1 Вложенные циклы


В результате генерации получаем одномерную структуру.

Важно! При работае с вложенными циклами внутри генератора выражений порядок следования инструкций for in будет такой же (слева-направо), как и в аналогичном решении без генератора, только на циклах (сверху-вниз)! Тоже справедливо и при более глубоких уровнях вложенности.

7.1.1 Вложенные циклы for где циклы идут по независимым итераторам


Общий синтаксис: [expression for x in iter1 for y in iter2]
Применение: генерируем одномерную структуру, используя данные из двух итераторов.

Например, создадим словарь, используя кортежи координат как ключи, заполнив для начала его значения нулями.

rows = 1, 2, 3
cols = 'a', 'b'
my_dict = {(col, row): 0 for row in rows for col in cols}
print(my_dict)  # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}

Дальше можем задавать новые значения или получать их
my_dict['b', 2] = 10   # задаем значение по координатному ключу-кортежу
print(my_dict['b', 2])   # 10 - получаем значение по координатному ключу-кортежу

Тоже можно сделать и с дополнительными условиями-фильтрами в каждом цикле:
rows = 1, 2, 3, -4, -5
cols = 'a', 'b', 'abc'
# Для наглядности разнесем на несколько строк
my_dict = {
    (col, row): 0  # каждый элемент состоит из ключа-кортежа и нулевого знаечния
    for row in rows if row > 0   # Только положительные значения
    for col in cols if len(col) == 1  # Только односимвольные
    }
print(my_dict)  # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}

Эта же задача решенная с помощью цикла
rows = 1, 2, 3, -4, -5
cols = 'a', 'b', 'abc'
my_dict = {}
for row in rows:
    if row > 0:
        for col in cols:
            if len(col) == 1:
                my_dict[col, row] = 0
print(my_dict)  # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}

7.1.2 Вложенные циклы for где внутренний цикл идет по результату внешнего цикла


Общий синтаксис: [expression for x in iterator for y in x].

Применение: Стандартный подход, когда нам надо обходить двумерную структуру данных, превращая ее в «плоскую» одномерную. В данном случае, мы во внешнем цикле проходим по строкам, а во внутреннем по элементам каждой строки нашей двумерной структуры.

Допустим у нас есть двумерная матрица — список списков. И мы желаем преобразовать ее в плоский одномерный список.

matrix = [[0, 1, 2, 3],
          [10, 11, 12, 13],
          [20, 21, 22, 23]]

# Решение с помощью генератора списка:
flattened = [n for row in matrix for n in row]
print(flattened)    # [0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23]

Таже задача, решенная с помощью вложенных циклов
flattened = []
for row in matrix:
    for n in row:
        flattened.append(n)
print(flattened)

UPD:Изящные решения из комментариев
import itertools
flattened = list(itertools.chain.from_iterable(matrix))  # от @iMrDron
# Данный подходнамного быстрее генератора списков 
# и рекомендован к использованию для подобных задач.

flattened = sum(a, [])  # от @YuriM1983
# sum(a, []) имеет квадратическую сложность(O(n^2)) 
# и потому совсем не рекомендуется к использованию для таких целей

7.2 Вложенные генераторы


Вложенными могут быть не только циклы for внутри выражения-генератора, но и сами генераторы.
Такой подход применяется когда нам надо строить двумерную структуру.

Важно!: В отличии от примеров выше с вложенными циклами, для вложенных генераторов, вначале обрабатывается внешний генератор, потом внутренний, то есть порядок идет справа-налево.

Ниже рассмотрим два варианта подобного использования.

7.2.1 — Вложенный генератор внутри генератора — двумерная из двух одномерных


Общий синтаксис: [[expression for y in iter2] for x in iter1]
Применение: генерируем двумерную структуру, используя данные из двух одномерных итераторов.

Для примера создадим матрицу из 5 столбцов и 3 строк и заполним ее нулями:

w, h = 5, 3  # зададим ширину и высотку матрицы
matrix = [[0 for x in range(w)] for y in range(h)]
print(matrix)   # [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

Создание этой же матрицы двумя вложенными циклами — обратите внимание на порядок вложения
matrix = []
for y in range(h):
    new_row = []
    for x in range(w):
        new_row.append(0)
    matrix.append(new_row)
print(matrix)   # [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

Примечание: После создания можем работать с матрицей как с обычным двумерным массивом
# теперь можно добавлять значения по координатам (координаты - индексы в списке списков)
matrix[0][0] = 1
matrix[1][3] = 3
print(matrix)   # [[1, 0, 0, 0, 0], [0, 0, 0, 3, 0], [0, 0, 0, 0, 0]]

# Получаем значение по произвольным координатам
x, y = 1, 3
print(matrix[x][y])  # 3

7.2.2 — Вложенный генератор внутри генератора — двумерная из двумерной


Общий синтаксис: [[expression for y in x] for x in iterator]
Применение: Обходим двумерную структуру данных, сохраняя результат в другую двумерную структуру.

Возьмем матрицу:

matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]

Возведем каждый элемент матрицы в квадрат:
squared = [[cell**2 for cell in row] for row in matrix]
print(squared)    # [[1, 4, 9, 16], [25, 36, 49, 64], [81, 100, 121, 144]]

Эта же операция в виде вложенных циклов
squared = []
for row in matrix:
    new_row = []
    for cell in row:
        new_row.append(cell**2)
    squared.append(new_row)
print(squared)    # [[1, 4, 9, 16], [25, 36, 49, 64], [81, 100, 121, 144]]

Обобщим все вышеперечисленные варианты в одной схеме (полный размер по клику):

7.3 — Генератор итерирующийся по генератору


Так как любой генератор может использоваться как итератор в цикле for, это так же можно использовать и для создания генератора по генератору.
При этом синтаксически это может записываться в два выражения или объединяться во вложенный генератор.

Проиллюстрирую и такую возможность.
Допустим у нас есть два таких генератора списков:

list_a = [x for x in range(-2, 4)]    # Так сделано для дальнейшего примера синтаксиса, 
                                      # конечно в подобной задаче досточно только range(-2, 4)
list_b = [x**2 for x in list_a]

Тоже самое можно записать и в одно выражение, подставив вместо list_a его генератор списка:
list_c = [x**2 for x in [x for x in range(-2, 4)]]
print(list_c)  # [4, 1, 0, 1, 4, 9]

UPD от longclaps: Преимущество от комбинирования генераторов на примере сложной функции f(x) = u(v(x))
list_c = [t + t ** 2  for t in (x ** 3 + x ** 4 for x in range(-2, 4))]

8. Использование range()


Говоря о способах генерации коллекций, нельзя обойти вниманием простую и очень удобную функцию range(), которая предназначена для создания арифметических последовательностей.
Особенности функции range():

  • Наиболее часто функция range() применяется для запуска цикла for нужное количество раз. Например, смотрите генерацию матрицы в примерах выше.
  • В Python 3 range() возвращает генератор, который при каждом к нему обращении выдает очередной элемент.
  • Исполльзуемые параметры аналогичны таковым в срезах (кроме первого примера с одним параметром):
    • range(stop) — в данном случае с 0 до stop-1;
    • range(start, stop) — Аналогично примеру выше, но можно задать начало отличное от нуля, можно и отрицательное;
    • range(start, stop, step) — Добавляем параметр шага, который может быть отрицательным, тогда перебор в обратном порядке.

  • В Python 2 были 2 функции:
    • range(…) которая аналогична выражению list(range(…)) в Python 3 — то есть она выдавала не итератор, а сразу готовый список. То есть все проблемы возможной нехватки памяти, описанные в разделе 4 актуальны, и использовать ее в Python 2 надо очень аккуратно!
    • xrange(…) — которая работала аналогично range(…) в Python 3 и из 3 версии была исключена.

Примеры использования:
print(list(range(5)))           # [0, 1, 2, 3, 4]
print(list(range(-2, 5)))       # [-2, -1, 0, 1, 2, 3, 4]
print(list(range(5, -2, -2)))   # [5, 3, 1, -1]

9. Приложение 1. Дополнительные примеры


9.1 Последовательный проход по нескольким спискам
import itertools
l1 = [1,2,3]
l2 = [10,20,30]
result = [l*2 for l in itertools.chain(l1, l2)]
print(result)   # [2, 4, 6, 20, 40, 60]

9.2 Транспозиция матрицы
(Преобразование матрицы, когда строки меняются местами со столбцами).

Возьмем матрицу.

matrix = [[1, 2, 3, 4],
          [5, 6, 7, 8],
          [9, 10, 11, 12]]

Сделаем ее транспозицию с помощью генератора выражений:
transposed = [[row[i] for row in matrix] for i in range(len(matrix[0]))]
print(transposed)  # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

Эта же транспозиция матрицы в виде цикла
transposed = []
for i in range(len(matrix[0])):
    new_row = []
    for row in matrix:
        new_row.append(row[i])
    transposed.append(new_row)
print(transposed)  # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

И немного черной магии от @longclaps
transposed = list(map(list, zip(*matrix)))
print(transposed)  # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

9.3 Задача выбора только рабочих дней
# Формируем список дней от 1 до 31 с которым будем работать
days = [d for d in range(1, 32)]

# Делим список дней на недели
weeks = [days[i:i+7] for i in range(0, len(days), 7)]
print(weeks)   # [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14], [15, 16, 17, 18, 19, 20, 21], [22, 23, 24, 25, 26, 27, 28], [29, 30, 31]]

# Выбираем в каждой неделе только первые 5 рабочих дней, отбрасывая остальные
work_weeks = [week[0:5] for week in weeks]
print(work_weeks)   # [[1, 2, 3, 4, 5], [8, 9, 10, 11, 12], [15, 16, 17, 18, 19], [22, 23, 24, 25, 26], [29, 30, 31]]

# Если нужно одним списком дней - можно объединить
wdays = [item for sublist in work_weeks for item in sublist]
print(wdays)   # [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31]

Можно убрать выходные еще более изящно, используя только индексы
# Формируем список дней от 1 до 31 с которым будем работать
days = [d for d in range(1, 32)]

wdays6 = [wd for (i, wd) in enumerate(days, 1) if i % 7 != 0]  # Удаляем каждый 7-й день
# Удаляем каждый 6 день в оставшихся после первого удаления:
wdays5 = [wd for (i, wd) in enumerate(wdays6, 1) if i % 6 != 0]

print(wdays5)
# [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31]

# Обратите внимание, что просто объединить два условия в одном if не получится,
# как минимум потому, что 12-й день делится на 6, но не выпадает на последний 2 дня недели!

# Шикарное короткое решение от @sophist:
days = [d + 1 for d in range(31) if d % 7 < 5]

10. Приложение 2. Ссылки по теме


  1. Хорошая англоязычная статья с детальным объяснением что такое генераторы и итераторыИллюстрация из статьи:

  2. Если у Вас есть сложности с пониманием логики работы с генераторными выражениями, посмотрите интересную англоязычную статью, где проводятся аналогии между генераторными выражениями и работой с SQL и таблицами Excel.Например так:
    squared_evens = [n ** 2              # SELECT
                    for n in numbers    # FROM
                    if n % 2 == 0]      # WHERE

  3. UPD от fireSparrow: Существуюет расширение Python — PythonQL, позволяющее работать с базами данных в стиле генераторов коллекций.
  4. Иллюстрированная статья на английском, довольно наглядно показывает синтаксис генераторных выражений.
  5. Если требуются дополнительные примеры по теме вложенных генераторных выражений (статья на английском).


Приглашаю к обсуждению:

  • Если я где-то допустил неточность или не учёл что-то важное — пишите в комментариях, важные комментарии будут позже добавлены в статью с указанием вашего авторства.
  • Если какие-то моменты не понятны и требуется уточнение — пишите ваши вопросы в комментариях — или я или другие читатели дадут ответ, а дельные вопросы с ответами будут позже добавлены в статью.

Генератор прямоугольного импульса. Функции генератора. Управление функциональным генератором

Генератор прямоугольного импульса

Т80 я и HS801 могут использовать генератор  прямоугольных импульсов.

[Здесь должен быть рисунок]

Частотный вход можно использовать для калибровки исследуемого сигнала

Частотный выход генерирует сигнал прямоугольного импульса, изменяющийся от -2.5 до + 2.5 вольт, и имеет переменную частоту между 100 Гц и 100 кГц.

Выбирают частотный диапазон, нажимая одну из кнопок. Более точную частоту можно установить с помощью движка. Текущая частота отображена выше движка.

Когда частота установлена, можно включить генератор. Это происходит при нажатии клавишного выключателя, который находится справа. По щелчку можно понять, что генератор включен.

Когда программа закрыта, то выбранная частота генератора сохраняется, до следующего включения генератора.

-119-

Функции генератора

TiePieSCOPE HS80 я AWG, Handyscope 3 и ТР80 я AWG имеют в наличии функциональный генератор.

При помощи функционального генератора сигнал может изменять свою форму, частоту, симметрию и может быть смещен.

Наряду с этим функциональный генератор содержит генератор развертки, который в комбинации с анализатором спектра, можно использовать для того, чтобы создавать частотные характеристики узлов или цепей.

Так же функциональный генератор предусматривает многие определяемые пользователем и предварительно установленные позиции.

Принцип функционального генератора

Функциональный генератор использует технологию ПЦС. ПЦС обозначает Прямой Цифровой Синтез, а принцип работы включает в себя основы обработки цифровых блоков данных, для генерации частотно-настраиваемого с синхронизированными часами точности сигнала. ПЦС позволяет генерировать сигналы  цифровым способом  с низким уровнем искажения  и очень точным частотным регулированием.

-121-

Структура функционального генератора

Функциональный генератор состоит из многих функциональных блоков.

Наверху показывается  форма сигнала и другие регулировки функционального генератора. Слева показаны формы, которые может принять сигнал. Ниже показано, каким образом можно управлять частотой, симметрией, амплитудой и смещением сигнала. Справа показаны клавиши для численного задания параметров и клавиатура для предварительных установок.

Эта часть экрана может быть скрыта, с помощью маленькой кнопки в правом верхнем углу функционального генератора. Так же функциональный генератор ­может стать более маленьким и занимать  меньше места на компьютерном экране. При повторном нажатии на кнопку окно станет прежним. То же самое может быть получено, при нажатии кнопки <Shift — < > и <Shift -> >.

Управление функциональным генератором

Форма сигнала

[Здесь должен быть рисунок]

Форма сигнала может быть установлена при нажатии на кнопку. Возможные формы сигналы:

Синус  — генерируется синусоида

Треугольник — генерируется треугольный импульс

Квадрат — генерируется прямоугольный импульс

Цифровой синтез — генерируется постоянный уровень ПЦС

Белый шум — генерируется белый шум

Файл — генерируется сигнал от файла

О сигнальном типе Файл будет рассказано позже.

-122-

Частота

[Здесь должен быть рисунок]

В Частотном блоке есть все функции для управления частотой сигнала. Семь декадных кнопок устанавливают частотный диапазон, в котором ­может быть установлена частота. Диапазон устанавливается при помощи движка. Диапазон может быть задан от 0,2 до 2

Когда форма сигнала установлена в ПЦС, частотное регулирование — отключено.

Симметрия

[Здесь должен быть рисунок]

Симметрия сигнала указывает соотношение между длиной положительной части периода к полной длине периода. Симметрия 50 % показывает, что положительная часть — точно ровна половине полного периода.

При помощи  движка  в блоке Симметрии, симметрия может быть задана от 1 до 99%. Кнопка середина (mid) устанавливает симметрию в 50 %, от центрального положения.

Когда сигнальная форма установлена в ПЦС или Белый шум, то регулирование симметрии отключено.

Амплитуда

[Здесь должен быть рисунок]

Амплитуда Выходного сигнала может быть использована при трех значениях амплитуды: не ослабленный,  -20 децибел ослабления или -40 децибел ослабления. При помощи движка напряжение может быть установлено между 0 Вольт и 12 вольтами (или 0 Вольт и 10 вольт, зависит от выбранного инструмента).

-123-

 ПЦС смещение

Это возможность прибавить смещение ЦС к сигналу выхода. В блоке Смещения ЦС есть движок, которым можно регулировать амплитуду смещения. Кнопка 0 обнулит смещение ЦС

Когда форма сигнала установлена в ЦС, движок используется, чтобы переключить полярность ­ ЦС сигнала.

Численный вход.

Всеми выше описанными функциями можно также управлять, при помощи клавиатуры. Когда окно расширенно, можно увидеть маленькую клавиатуру, которая позволяет вводить все параметры настройки.

Этой клавиатурой можно управлять как мышью, так и при  помощи клавиатуры компьютера. В этом случае, окно не должно быть расширено.

Четыре кнопки указывают, какое управление будет использовано. Соответствующая кнопка будет показан и начнет мигать. Также номерованные кнопки будут разрешены, и нужная величина может быть введена. Вход будет закончен, при нажатии <Enter>  на кнопку.

Доступны следующие кнопки:

-124-

S          Используйте симметрию сигнала            

D         Используйте ответвление ЦС сигнала

A         Используйте амплитуду сигнала

F          Используйте частоту сигнала

0..9      Прибавьте цифру к введенному номеру

.           Прибавьте точку  к введенному номеру

—          Полностью измените полярность введенного номера

C         Ограничьте вход

<—        Переместите последний введенный отличительный признак

<-/       Закончите вход и примените его

Esc      Ограничьте вход

Предварительная установка

у функционального генератора есть 8 заданных положений, чтобы запомнить настройки параметров сигнала.

[Здесь должен быть рисунок]

При нажатии на кнопку, сигнал с указанной формой, амплитудой, смещением, частотой и симметрией может генерироваться

Предварительная установка сохраняется вместе с используемыми настройками и восстанавливается каждый раз, когда приложение запущено.

alexxlab

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *