Switch-конструкция с помощью словаря
К сожалению, в Python не существует switch-конструкций, в отличие от большинства других языков программирования, и поэтому приходится строить башни из условных операторов в своём коде.
Однако есть одно хитрое решение — использовать словарь, где значениями будут функции. Например, напишем словарь, который будет использован для математических операторов.
В этом примере были использованы lambda-функции для простоты, но вместо них можете подставить любые другие. Для тех, кто не знает: lambda - объявление анонимной функции (можно косвенно сравнить с def); x, y - принимаемые аргументы; x + y - то, что функция возвращает.
Примерно вот так мы можем пользоваться подобной штукой. Думаю, что многие найдут полезное применение подобному использованию словарей.
К сожалению, в Python не существует switch-конструкций, в отличие от большинства других языков программирования, и поэтому приходится строить башни из условных операторов в своём коде.
Однако есть одно хитрое решение — использовать словарь, где значениями будут функции. Например, напишем словарь, который будет использован для математических операторов.
switch = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y
}
В этом примере были использованы lambda-функции для простоты, но вместо них можете подставить любые другие. Для тех, кто не знает: lambda - объявление анонимной функции (можно косвенно сравнить с def); x, y - принимаемые аргументы; x + y - то, что функция возвращает.
result = switch['*'](4, 5)
print(result)
# Output: 20
Примерно вот так мы можем пользоваться подобной штукой. Думаю, что многие найдут полезное применение подобному использованию словарей.
Как одной математической формулой по номеру месяца посчитать количество дней в нем?
Попробуем написать функцию f(x), которая бы давала следующий список значений (таблица №1), то есть количество дней в месяцах. Помимо стандартных арифметических операций, мы будем использовать целочисленное деление и взятие остатка по модулю.
Обычно количество дней в месяце колеблется между 30 и 31. При этом, можно заметить зависимость этого числа от четности месяца — значит, воспользуемся операцией взятия остатка по модулю 2. Кажется, это должно быть нечто, вроде:
Пока что не обращая внимания на февраль, нам нужно, чтобы +1 в делимом «активировалось» только при достижении аргументом значений, больших 8. При этом значения аргумента не могут превосходить 12. Значит, нам идеально подойдет целочисленное деление аргумента на 8:
Все правильно, кроме февраля. Как неожиданно. В самой последней версии нашей формулы февралю достались целых 30 дней. А потому нам нужно отсечь у него пару дней. Естественно, от этого пострадают и еще какие-то месяцы, поэтому нам придется пожертвовать именно январем, затем подправив формулу и для него. Отсечь дни для первого и второго месяцев можно с помощью выражения 2 % x. Тогда наша формула принимает уже следующий вид:
Остался последний шаг — подлатать январь. Это сделать не так сложно: просто добавим 2 дня только к нему, т.е. к такому месяцу, чей номер меньше либо равен единице. Как вам идея использовать для этой цели
Превосходно, 12 из 12. Подобная функция на языке Python может быть записана следующим образом:
Попробуем написать функцию f(x), которая бы давала следующий список значений (таблица №1), то есть количество дней в месяцах. Помимо стандартных арифметических операций, мы будем использовать целочисленное деление и взятие остатка по модулю.
Обычно количество дней в месяце колеблется между 30 и 31. При этом, можно заметить зависимость этого числа от четности месяца — значит, воспользуемся операцией взятия остатка по модулю 2. Кажется, это должно быть нечто, вроде:
f₁(x) = 30 + x % 2
# таблица №2
Пока что не обращая внимания на февраль, нам нужно, чтобы +1 в делимом «активировалось» только при достижении аргументом значений, больших 8. При этом значения аргумента не могут превосходить 12. Значит, нам идеально подойдет целочисленное деление аргумента на 8:
f₃(x) = 30 + (x + x // 8) % 2
# таблица №3
Все правильно, кроме февраля. Как неожиданно. В самой последней версии нашей формулы февралю достались целых 30 дней. А потому нам нужно отсечь у него пару дней. Естественно, от этого пострадают и еще какие-то месяцы, поэтому нам придется пожертвовать именно январем, затем подправив формулу и для него. Отсечь дни для первого и второго месяцев можно с помощью выражения 2 % x. Тогда наша формула принимает уже следующий вид:
f₄(x) = 28 + (x + x // 8) % 2 + 2 % x
# таблица №4
Остался последний шаг — подлатать январь. Это сделать не так сложно: просто добавим 2 дня только к нему, т.е. к такому месяцу, чей номер меньше либо равен единице. Как вам идея использовать для этой цели
1 // x
? Проверяем:f₅(x) = 28 + (x + x // 8) % 2 + 2 % x + 1 // x * 2
# таблица №5
Превосходно, 12 из 12. Подобная функция на языке Python может быть записана следующим образом:
f = lambda x: 28 + (x + x // 8) % 2 + 2 % x + 1 // x * 2
print(f'В июне {f(6)} дней')
# Out: В июне 30 дней
urlencode
Довольно часто приходится работать с разнообразными API и совершать get-запросы с передачей множества параметров. Чаще всего составление запроса в коде выглядит примерно так:
Смотрится не слишком презентабельно, однако есть слегка длиннее, но значительно улучающий читаемость вариант – функция urlencode из из модуля urllib:
P. S. Приносим извинения за настолько долгое отсутствие постов, возобновляем работу над каналом.
Довольно часто приходится работать с разнообразными API и совершать get-запросы с передачей множества параметров. Чаще всего составление запроса в коде выглядит примерно так:
url = 'https://example.com?item={}&size={}&color={}&amount={}'.format('t-shirt', 'M', 'white', 5)
Смотрится не слишком презентабельно, однако есть слегка длиннее, но значительно улучающий читаемость вариант – функция urlencode из из модуля urllib:
from urllib.parse import urlencode
url = 'https://example.com'
params = {
'item': 't-shirt',
'size': 'M',
'color': 'white',
'amount': 5
}
encoded_params = urlencode(params)
url += '?' + encoded_params
print(url)
# Output: example.com?item=t-shirt&size=M&color=white&amount=5
P. S. Приносим извинения за настолько долгое отсутствие постов, возобновляем работу над каналом.
Абстрактные методы в Python
В абстрактном классе обычно реализуется общая часть нескольких сущностей или другими словами - абстрактная сущность.
Абстрактный метод – это метод, который не имеет своей реализации в базовом классе, и он должен быть реализован в классе-наследнике.
Для того, чтобы создать абстрактный класс с абстрактными методами, надо импортировать вспомогательные метакласс ABCMeta и декоратор abstractmethod из модуля abc.
Если мы отнаследуем новый класс от абстрактного класса, не переопределив абстрактные методы (в данном случае function), и попробуем создать экземпляр, то получим исключение:
Для того, чтобы код заработал корректно, нам необходимо переопределить все абстрактные методы. То есть по сути еще раз просто написать функцию, но уже в новом классе.
В абстрактном классе обычно реализуется общая часть нескольких сущностей или другими словами - абстрактная сущность.
Абстрактный метод – это метод, который не имеет своей реализации в базовом классе, и он должен быть реализован в классе-наследнике.
Для того, чтобы создать абстрактный класс с абстрактными методами, надо импортировать вспомогательные метакласс ABCMeta и декоратор abstractmethod из модуля abc.
from abc import ABCMeta, abstractmethod
class AbstractClass(metaclass=ABCMeta):
@abstractmethod
def function(self):
pass
Если мы отнаследуем новый класс от абстрактного класса, не переопределив абстрактные методы (в данном случае function), и попробуем создать экземпляр, то получим исключение:
class BadExample(AbstractClass):
pass
child = BadExample()
# TypeError: Can't instantiate abstract class BadExample with abstract methods function
Для того, чтобы код заработал корректно, нам необходимо переопределить все абстрактные методы. То есть по сути еще раз просто написать функцию, но уже в новом классе.
class GoodExample(AbstractClass):
def function(self):
print('Everything is ok')
anotherchild = GoodExample()
Паттерн проектирования Singleton
Одиночка или же синглтон – это паттерн проектирования, описывающий объект, у которого имеется один единственный экземпляр.
Итак, нам требуется такой класс, который будет при вызове возвращать один и тот же экземпляр, поэтому нам придется переопределить магический метод new.
new__(cls, *args, **kwargs) –– вызывается для создания экземпляра класса, перед вызовом __init. На вход первым аргументом метод принимает сам класс, а возвращать должен уже экземпляр (даже можно экземпляр и другого класса).
Здесь мы проверяем, есть ли значение у атрибута instance. Если нет, то присваиваем атрибуту экземпляр этого же класса. А если уже экземпляр создан, то просто его возвращаем.
То есть при вызове конструктора класса Singleton, будет возвращаться один и тот же объект из памяти.
Создали два экземпляра, теперь убедимся, что они содержат одинаковый объект.
Одиночка или же синглтон – это паттерн проектирования, описывающий объект, у которого имеется один единственный экземпляр.
Итак, нам требуется такой класс, который будет при вызове возвращать один и тот же экземпляр, поэтому нам придется переопределить магический метод new.
new__(cls, *args, **kwargs) –– вызывается для создания экземпляра класса, перед вызовом __init. На вход первым аргументом метод принимает сам класс, а возвращать должен уже экземпляр (даже можно экземпляр и другого класса).
class Singleton:
instance = None
def __new__(cls):
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
Здесь мы проверяем, есть ли значение у атрибута instance. Если нет, то присваиваем атрибуту экземпляр этого же класса. А если уже экземпляр создан, то просто его возвращаем.
То есть при вызове конструктора класса Singleton, будет возвращаться один и тот же объект из памяти.
a = Singleton()
b = Singleton()
Создали два экземпляра, теперь убедимся, что они содержат одинаковый объект.
print(a is b) # True
Модуль os
В данном посте мы не будем изучать от начала до конца этот модуль, а просто пройдемся по основным методам. Вкратце, os предоставляет функции для работы с операционной системой.
1. Отображение текущей рабочей директории.
2. Получение списка папок и файлов в текущей директории.
3. Смена рабочей директории.
4. Создание и удаление папок.
5. Отправка команд в терминал.
В данном посте мы не будем изучать от начала до конца этот модуль, а просто пройдемся по основным методам. Вкратце, os предоставляет функции для работы с операционной системой.
1. Отображение текущей рабочей директории.
>>> os.getcwd()
'/Users/Adrian'
2. Получение списка папок и файлов в текущей директории.
>>> os.listdir()
['Music', 'Pictures', 'Desktop', 'Library', 'Public', 'Movies', 'Applications', 'Documents', 'Downloads']
3. Смена рабочей директории.
>>> os.chdir('Documents')
4. Создание и удаление папок.
>>> os.mkdir('new_folder')
>>> os.rmdir('new_folder')
5. Отправка команд в терминал.
>>> os.system('echo hello')
hello
Неправильное использование выражений как значений по умолчанию для аргументов функции
Python позволяет указать, что аргумент функции является необязательным, предоставив для него значение по умолчанию. Хотя это отличная особенность языка, она может привести к некоторой путанице, когда значение по умолчанию является изменяемым. Например, рассмотрим определение такой функции:
Распространенной ошибкой является мысль, что для необязательного аргумента будет задано указанное выражение по умолчанию каждый раз, когда вызывается функция, без указания значения для необязательного аргумента. Например, в приведенном выше коде можно ожидать, что повторный вызов foo() всегда будет возвращать ['baz'], поскольку предполагается, что каждый раз, когда вызывается foo(), bar установлен на [].
Ответ на вопрос “почему так происходит?” заключается в том, что значение по умолчанию для аргумента функции создается только один раз, во время определения функции. Таким образом, аргумент bar инициализируется по умолчанию только тогда, когда foo() определен впервые, но затем вызовы foo() продолжат использовать тот же список для какой bar был изначально инициализирован.
Чаще всего такую ситуацию обходят примерно следующим образом:
Python позволяет указать, что аргумент функции является необязательным, предоставив для него значение по умолчанию. Хотя это отличная особенность языка, она может привести к некоторой путанице, когда значение по умолчанию является изменяемым. Например, рассмотрим определение такой функции:
>>> def foo(bar=[]):
... bar.append('baz')
... return bar
Распространенной ошибкой является мысль, что для необязательного аргумента будет задано указанное выражение по умолчанию каждый раз, когда вызывается функция, без указания значения для необязательного аргумента. Например, в приведенном выше коде можно ожидать, что повторный вызов foo() всегда будет возвращать ['baz'], поскольку предполагается, что каждый раз, когда вызывается foo(), bar установлен на [].
>>> foo()
['baz']
>>> foo()
['baz', 'baz']
>>> foo()
['baz', 'baz', 'baz']
Ответ на вопрос “почему так происходит?” заключается в том, что значение по умолчанию для аргумента функции создается только один раз, во время определения функции. Таким образом, аргумент bar инициализируется по умолчанию только тогда, когда foo() определен впервые, но затем вызовы foo() продолжат использовать тот же список для какой bar был изначально инициализирован.
Чаще всего такую ситуацию обходят примерно следующим образом:
>>> def foo(bar=None):
... if bar is None:
... bar = []
... bar.append('baz')
... return bar
...
>>> foo()
['baz']
>>> foo()
['baz']
>>> foo()
['baz']
# test
Рубрика #Проекты
Буквально вчера я закончил переписывать того самого бота, который давал погоду в визуальном формате. Из глобальных обновлений: появилась возможность смены языка и просмотр публичной статистики.
И теперь этот бот доступен по новой ссылке – @TeleWeatherRobot
А также делюсь с вами исходным кодом – https://github.com/adreex/TeleWeatherBot (поставьте звездочку проекту, плз)
P. S. буду благодарен за все баг-репорты в лс или в чат канала.
Буквально вчера я закончил переписывать того самого бота, который давал погоду в визуальном формате. Из глобальных обновлений: появилась возможность смены языка и просмотр публичной статистики.
И теперь этот бот доступен по новой ссылке – @TeleWeatherRobot
А также делюсь с вами исходным кодом – https://github.com/adreex/TeleWeatherBot (поставьте звездочку проекту, плз)
P. S. буду благодарен за все баг-репорты в лс или в чат канала.
Python packages
Предположим, вы разрабатываете большое приложение, которое включает в себя множество модулей. Очевидно, что складывать всё в одну папку не просто неудобно, а в некоторых случаях даже нерационально. Создадим для примера модуль
Модуль
В
Предположим, что у нас есть уже какие-то функции в
Точка указывает на то, что мы импортируем модули из этого же пакета, а не откуда-то еще. Если указать без точки или просто
Теперь в
Возможности пакетов и модулей в Python этим не ограничиваются, но для вступления и ознакомления этой информации должно хватить.
Предположим, вы разрабатываете большое приложение, которое включает в себя множество модулей. Очевидно, что складывать всё в одну папку не просто неудобно, а в некоторых случаях даже нерационально. Создадим для примера модуль
main.py
и рядом с ним пакет с модулями (папку с файлами) примерно в таком виде:├── main.py
└── package
├── __init__.py
├── module1.py
└── module2.py
Модуль
__init__.py
нужен для инициализации пакета, а также он вызывается при импорте пакета или модулей из него. Тем не менее, __init__.py
может был пустым, достаточно его присутствия. Простыми словами, такой модуль нужен для того, работать с папкой как с Python-пакетом.В
main.py
мы уже можем импортировать пакет и модули примерно такими способами:import package
from package import module1
import package.module2 as m2
Предположим, что у нас есть уже какие-то функции в
module1.py
и module2.py
. Теперь давайте напишем кое-что в __init__.py
для примера:from .module1 import function1
from . import module2 as m2
variable = 'hello from __init__.py'
Точка указывает на то, что мы импортируем модули из этого же пакета, а не откуда-то еще. Если указать без точки или просто
import module2
, то возникнет исключение.Теперь в
main.py
мы можем выполнить следующие команды:from package import function1
from package import m2
from package import variable
Возможности пакетов и модулей в Python этим не ограничиваются, но для вступления и ознакомления этой информации должно хватить.
Изменение списка во время итерации по нему
Предположим, что требуется удалить все нечетные числа из списка. Проблема со следующим кодом должна быть довольно очевидной:
Удаление элемента из списка во время его итерации – это проблема, которая хорошо известна любому опытному разработчику.
К счастью, Python включает в себя ряд элегантных парадигм программирования, которые при правильном использовании могут привести к значительному упрощению и оптимизации кода. Одна из таких парадигм – list comprehensions. Генераторы списков часто используют именно для решение подобных проблем, что и показывает реализация кода ниже:
Предположим, что требуется удалить все нечетные числа из списка. Проблема со следующим кодом должна быть довольно очевидной:
odd = lambda x: bool(x % 2) # функция проверки числа на нечетность
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in range(10):
if odd(numbers[i]):
del numbers[i] # удаление элемента из списка во время итерации по нему
# Output:
Traceback (most recent call last):
if odd(numbers[i]):
IndexError: list index out of range
Удаление элемента из списка во время его итерации – это проблема, которая хорошо известна любому опытному разработчику.
К счастью, Python включает в себя ряд элегантных парадигм программирования, которые при правильном использовании могут привести к значительному упрощению и оптимизации кода. Одна из таких парадигм – list comprehensions. Генераторы списков часто используют именно для решение подобных проблем, что и показывает реализация кода ниже:
odd = lambda x: bool(x % 2) # функция проверки числа на нечетность
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers = [n for n in numbers if not odd(n)] # генератор нового списка
print(numbers)
# Output:
[2, 4, 6, 8, 10]
Форматирование строк
В этом посте разберем доступные в Python методы форматирования строк. Для начала определим две переменные, которые потом и будем вставлять в строки.
Самый древний и уже редко используемый способ – с помощью оператора %. Написание %s и %d зависит от того, что мы туда передаем и что хотим увидеть в итоге, но это уже тема отдельного поста.
В Python 2.6 появился метод .format() с немного отличающимся синтаксисом от существующего оператора %. К слову, этот метод активно используется и по сей день, в отличии от его предшественника.
Начиная с версии Python 3.6, доступны f-строки – свежий и наиболее производительный способ форматирования строк.
В этом посте разберем доступные в Python методы форматирования строк. Для начала определим две переменные, которые потом и будем вставлять в строки.
name = 'Adrian'
age = 17
Самый древний и уже редко используемый способ – с помощью оператора %. Написание %s и %d зависит от того, что мы туда передаем и что хотим увидеть в итоге, но это уже тема отдельного поста.
'My name is %s and I am %d years old' % (name, age)
В Python 2.6 появился метод .format() с немного отличающимся синтаксисом от существующего оператора %. К слову, этот метод активно используется и по сей день, в отличии от его предшественника.
'My name is {} and I am {} years old'.format(name, age)
Начиная с версии Python 3.6, доступны f-строки – свежий и наиболее производительный способ форматирования строк.
f'My name is {name} and I am {age} years old'
Аннотации типов
Всем известно, что Python – язык с динамической типизацией. Аннотации типов нужны для того, чтобы повысить информативность исходного кода, но они никак не влияют на поведение программы.
Для примера потребуется импортировать типы
Типы данных указывается через двоеточие после именно переменной после её создания. Создадим словарь с числами и сразу же список, состоящий из значений этого словаря:
Потом создадим функцию, возвращающую сумму переданных значений. В аргументах точно так же можно указывать их типы, а также через стрелочку можно указать типа возвращаемого значения:
Теперь используем эту функцию, передав туда распакованный список:
Однако помните, что аннотации типов не влияют на ход исполнения программы, поэтому в ранее написаную функцию мы с таким же успехом можем передать и строки, хотя указывали целочисленный типа данных:
Всем известно, что Python – язык с динамической типизацией. Аннотации типов нужны для того, чтобы повысить информативность исходного кода, но они никак не влияют на поведение программы.
Для примера потребуется импортировать типы
List
(список) и Dict
(словарь) из модуля typing
:from typing import List, Dict
Типы данных указывается через двоеточие после именно переменной после её создания. Создадим словарь с числами и сразу же список, состоящий из значений этого словаря:
numbers: Dict[str, int] = {'one': 1, 'two': 2}
values: List[int] = numbers.values()
Потом создадим функцию, возвращающую сумму переданных значений. В аргументах точно так же можно указывать их типы, а также через стрелочку можно указать типа возвращаемого значения:
def sum(a: int, b: int) -> int:
return a + b
Теперь используем эту функцию, передав туда распакованный список:
sum(*values)
# Output: 3
Однако помните, что аннотации типов не влияют на ход исполнения программы, поэтому в ранее написаную функцию мы с таким же успехом можем передать и строки, хотя указывали целочисленный типа данных:
sum('Python ', 'Lounge')
# Output: 'Python Lounge'
Генераторы
Выглядят функции-генераторы также как и обычные, но содержат выражения с ключевым словом yield для последовательного генерирования значений, которые могут быть использованы в циклах for, либо их получения при помощи функции next.
На каждой yield работа функции временно приостанавливается, при этом сохраняется состояние исполнения, включая локальные переменные, указатель на текущую инструкцию, внутренний стек и состояние обработки исключения. При последующем обращении к итератору генератора функция продолжает своё исполнение с места, на котором была приостановлена. Этим функции-генераторы отличаются от обычных функций, при вызове которых исполнение всякий раз начинается с начала.
Если функция достигает инструкции return, либо конца, возбуждается исключение StopIteration и итератор исчерпывает себя.
Теперь можно вызывать эту функцию и использовать функцию next.
Достаточно часто, а точнее практически всегда, генераторы используют в циклах for. Преимущество такого подхода в том, что можно получить все возможные значения и не словить ошибку StopIteration.
Теперь если вызвать функцию next еще раз, то получим то самое исключение.
Выглядят функции-генераторы также как и обычные, но содержат выражения с ключевым словом yield для последовательного генерирования значений, которые могут быть использованы в циклах for, либо их получения при помощи функции next.
На каждой yield работа функции временно приостанавливается, при этом сохраняется состояние исполнения, включая локальные переменные, указатель на текущую инструкцию, внутренний стек и состояние обработки исключения. При последующем обращении к итератору генератора функция продолжает своё исполнение с места, на котором была приостановлена. Этим функции-генераторы отличаются от обычных функций, при вызове которых исполнение всякий раз начинается с начала.
Если функция достигает инструкции return, либо конца, возбуждается исключение StopIteration и итератор исчерпывает себя.
def generator():
for item in ('first', 'second', 'third'):
yield item
Теперь можно вызывать эту функцию и использовать функцию next.
gen = generator()
value = next(gen)
print(value)
# Output: first
Достаточно часто, а точнее практически всегда, генераторы используют в циклах for. Преимущество такого подхода в том, что можно получить все возможные значения и не словить ошибку StopIteration.
for item in gen:
print(item, end=' ')
# Output: second third
Теперь если вызвать функцию next еще раз, то получим то самое исключение.
next(gen)
#
Output:Traceback (most recent call last):
File "main.py", line 12, in <module>
next(gen)
StopIteration
Генераторы коллекций
В Python есть специальная конструкция, позволяющая быстрее и удобнее создавать заполненные коллекции на основе имеющихся, при этом применяя какое-либо выражение к каждому элементу.
1. Генератор списка (list comprehension)
2. Генератор множества (set comprehension)
3. Генератор словаря (dictionary comprehension)
В Python есть специальная конструкция, позволяющая быстрее и удобнее создавать заполненные коллекции на основе имеющихся, при этом применяя какое-либо выражение к каждому элементу.
1. Генератор списка (list comprehension)
word = 'hello'
new_list = [c.upper() for c in word]
# ['H', 'E', 'L', 'L', 'O']
2. Генератор множества (set comprehension)
elements = [1, 2, 1, 3, 2]
new_set = {n * 0.1 for n in elements}
# {0.1, 0.2, 0.3}
3. Генератор словаря (dictionary comprehension)
numbers = {'one': 1, 'two': 2, 'three': 3}
new_dict = {v: k for k, v in numbers.items()}
# {1: 'one', 2: 'two', 3: 'three'}
yield from
Рассмотрим одну страшную конструкцию в Python 3.3+. Для начала напомню, генератор – это объект, который можно проитерировать только однажды. Записывается так:
Когда всего лишь один генератор – всё хорошо. Используем его как итератор и радуемся. Но не редки ситуации, в которых есть несколько генераторов:
И стоит задача – проитерировать сначала один генератор, потом второй. Но вернуть значения не в виде списка, а в виде нового генератора.
Здесь на помощь приходит следующая конструкция: yield from <expr>, где <expr> - выражение, вычисление которого даёт итерируемый объект, из которого и вычленяется итератор.
Используя yield form, поставленная выше задача решается так:
И теперь можно просто проитерироваться по полученному генератору, в итоге получив результаты обоих первоначальных генераторов. Воспользуемся генератором списка, работа которого показана в предыдущем посте.
Рассмотрим одну страшную конструкцию в Python 3.3+. Для начала напомню, генератор – это объект, который можно проитерировать только однажды. Записывается так:
def gen():
for x in range(100):
yield x
# Или покороче вот так
f = (x for x in range(100))
Когда всего лишь один генератор – всё хорошо. Используем его как итератор и радуемся. Но не редки ситуации, в которых есть несколько генераторов:
gen_1 = (x for x in range(5))
gen_2 = (x for x in range(5, 10))
И стоит задача – проитерировать сначала один генератор, потом второй. Но вернуть значения не в виде списка, а в виде нового генератора.
Здесь на помощь приходит следующая конструкция: yield from <expr>, где <expr> - выражение, вычисление которого даёт итерируемый объект, из которого и вычленяется итератор.
Используя yield form, поставленная выше задача решается так:
def generator():
yield from gen_1
yield from gen_2
gen = generator()
И теперь можно просто проитерироваться по полученному генератору, в итоге получив результаты обоих первоначальных генераторов. Воспользуемся генератором списка, работа которого показана в предыдущем посте.
result = [n for n in gen]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Перечисления
Python 3 поддерживает, благодаря классу Enum, простой механизм работы с перечислениями. Перечисления удобно использовать для хранения списков констант. Константы, в противном случае, оказываются беспорядочно разбросанными в коде.
from enum import Enum, auto
Из документации по Python 3 можно узнать о том, что перечисление — это набор символических имён, привязанных к уникальным, неизменным значениям. Члены одного перечисления можно сравнивать на идентичность. Перечисления можно обходить.
Python 3 поддерживает, благодаря классу Enum, простой механизм работы с перечислениями. Перечисления удобно использовать для хранения списков констант. Константы, в противном случае, оказываются беспорядочно разбросанными в коде.
from enum import Enum, auto
class Monster(Enum):
ZOMBIE = auto()
WARRIOR = auto()
BEAR = auto()
print(Monster.ZOMBIE)
# Monster.ZOMBIE
Из документации по Python 3 можно узнать о том, что перечисление — это набор символических имён, привязанных к уникальным, неизменным значениям. Члены одного перечисления можно сравнивать на идентичность. Перечисления можно обходить.
for monster in Monster:
print(monster)
# Monster.ZOMBIE
# Monster.WARRIOR
# Monster.BEAR
Python documentation
enum — Support for enumerations
Source code: Lib/enum.py Important: This page contains the API reference information. For tutorial information and discussion of more advanced topics, see Basic Tutorial, Advanced Tutorial, Enum Co...
Заходит однажды тестировщик программного обеспечения в бар. Забегает в бар. Пролезает в бар. Танцуя, проникает в бар. Крадется в бар. Врывается в бар. Прыгает в бар.
И заказывает 0 пива. Заказывает 99999 пив. Заказывает -1 пиво. Заказывает ящерицу в стакане. Заказывает "qwertyuiop". Заказывает одно пиво каждую милисекунду. Заказывает пиво, но отменяет заказ. Заказывает пиво вместе с 10000 посетителями одновременно. Заказывает пиво не заходя в бар. Заказывает drop table.
А кульминация этого анекдота находится на моем новом канале @dank_code
И заказывает 0 пива. Заказывает 99999 пив. Заказывает -1 пиво. Заказывает ящерицу в стакане. Заказывает "qwertyuiop". Заказывает одно пиво каждую милисекунду. Заказывает пиво, но отменяет заказ. Заказывает пиво вместе с 10000 посетителями одновременно. Заказывает пиво не заходя в бар. Заказывает drop table.
А кульминация этого анекдота находится на моем новом канале @dank_code
Распознавание лиц и верификация пользователей по ним – будущее или уже существующая реальность? Даже больше, каждый уже может написать свою подобную программу. Это настолько просто, что требуется буквально двадцать строк кода и всего лишь полчаса времени для понимания.
Читать статью
Читать статью
Teletype
Распознание и верификация по лицу с помощью Python
Вся информация представлена исключительно в образовательных целях, бла-бла-бла.
Функция map
На вход принимает два обязательных аргмумента: функция-обработчик и итерируемый объект, чаще всего это список. Суть map’a заключается в том, что он применяет переданную функцию к каждому элементу последовательности. А возвращает так называемый map-объект, который в дальнейшем можно конвертировать в обычный список и не только.
Обратите внимание, мы не пишем скобки у функции add_five при вызове map – это означает то, что мы передаем объект функции, а не результат её выполнения.
Тоже самое мы могли записать через анонимую функцию прямо в map'e.
Однако в данном примере нагляднее использовать генератор списка.
Хоть map и мощная функция, но лучше исходить от конкретных случаев. А вот вам действительно полезный пример из практики. Мы можем считать несколько чисел с консоли, которые вводят через пробел, разделив всё это функцией split.
На вход принимает два обязательных аргмумента: функция-обработчик и итерируемый объект, чаще всего это список. Суть map’a заключается в том, что он применяет переданную функцию к каждому элементу последовательности. А возвращает так называемый map-объект, который в дальнейшем можно конвертировать в обычный список и не только.
def add_five(a):
return a + 5
old_nums = [1, 2, 3, 4, 5]
new_nums = map(add_five, old_nums)
print(list(new_nums))
# Output: [6, 7, 8, 9, 10]
Обратите внимание, мы не пишем скобки у функции add_five при вызове map – это означает то, что мы передаем объект функции, а не результат её выполнения.
Тоже самое мы могли записать через анонимую функцию прямо в map'e.
old_nums = [1, 2, 3, 4, 5]
new_nums = map(lambda a: a + 5, old_nums)
print(list(new_nums))
# Output: [6, 7, 8, 9, 10]
Однако в данном примере нагляднее использовать генератор списка.
old_nums = [1, 2, 3, 4, 5]
new_nums = [a + 5 for a in old_nums]
print(new_nums)
# Output: [6, 7, 8, 9, 10]
Хоть map и мощная функция, но лучше исходить от конкретных случаев. А вот вам действительно полезный пример из практики. Мы можем считать несколько чисел с консоли, которые вводят через пробел, разделив всё это функцией split.
a, b, c = map(int, input().split())