UTF-8 — это кодировка с переменной длиной. Один символ может быть закодирован с использованием одного, двух, трёх или четырёх байтов. Это означает, что нельзя начать чтение строки в кодировке UTF-8 с произвольного байта, так как это может случайно разрушить символ:
Также это означает, что для пропуска первых
Однако можно пропустить фиксированное количество байтов, принимая во внимание некоторые особенности. Вот как может быть закодирован символ в UTF-8:
Как видно, байт является начальным байтом символа, если его вид не совпадает с
Пример использования:
👉@BookPython
In : lion = 'Löwe'
In : lion.encode('utf-8')[2:]
Out: b'\xb6we'
In : lion.encode('utf-8')[2:].decode('utf-8')
...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 0: invalid start byte
Также это означает, что для пропуска первых
N
символов строки их необходимо прочитать и декодировать. Рассчитать смещение заранее невозможно.Однако можно пропустить фиксированное количество байтов, принимая во внимание некоторые особенности. Вот как может быть закодирован символ в UTF-8:
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Как видно, байт является начальным байтом символа, если его вид не совпадает с
10xxxxxx
. Такие байты называются продолжением символа (continuation bytes). Давайте пропустим их:
def cut_bytes(s, n):
result = s.encode('utf-8')[n:]
mask = int('11000000', 2)
conbyte = int('10000000', 2)
while result[0] and result[0] & mask == conbyte:
result = result[1:]
return result.decode('utf-8')
Пример использования:
In : cut_bytes(lion, 2)
Out: 'we'
In : cut_bytes(lion, 1)
Out: 'öwe'
👉@BookPython
Иногда вам нужно запустить блок кода с несколькими контекстными менеджерами. Например:
Начиная с Python 2.7 и 3.1, это можно сделать с помощью одного выражения
До этого можно было использовать функцию
Однако в современных версиях Python эта функция устарела и вызывает предупреждение. Вместо неё рекомендуется использовать более продвинутый инструмент —
Это особенно полезно, когда количество контекстных менеджеров неизвестно заранее.
👉@BookPython
with open('f') as f:
with open('g') as g:
with open('h') as h:
pass
Начиная с Python 2.7 и 3.1, это можно сделать с помощью одного выражения
with
:
o = open
with o('f') as f, o('g') as g, o('h') as h:
pass
До этого можно было использовать функцию
contextlib.nested
:
with nested(o('f'), o('g'), o('h')) as (f, g, h):
pass
Однако в современных версиях Python эта функция устарела и вызывает предупреждение. Вместо неё рекомендуется использовать более продвинутый инструмент —
contextlib.ExitStack
. Он позволяет войти в любое количество контекстов в произвольное время, но гарантирует их корректное завершение:
from contextlib import ExitStack
with ExitStack() as stack:
f = stack.enter_context(o('f'))
g = stack.enter_context(o('g'))
other = [
stack.enter_context(o(filename))
for filename in filenames
]
Это особенно полезно, когда количество контекстных менеджеров неизвестно заранее.
👉@BookPython
Когда корутина asyncio хочет остановиться и взаимодействовать с циклом событий (event loop), она использует
Когда корутина ожидает (
Какое значение возвращает
Почему возникает эта ошибка? Как asyncio понимает, что это вы используете
👉@BookPython
await obj
(или yield from obj
до Python 3.6). Объект obj
должен быть другой корутиной, объектом asyncio.Future
или любым пользовательским объектом, похожим на Future
(любой объект, у которого определен метод __await__
).
async def coroutine():
await another_coroutine()
async def another_coroutine():
future = asyncio.Future()
await future
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
Когда корутина ожидает (
await
) другую корутину, вторая начинает выполняться вместо первой. Если она ожидает третью, то выполняется третья. Это продолжается до тех пор, пока какая-нибудь корутина не ожидает объект Future
. Объект Future
фактически возвращает значение, и тогда цикл событий (event loop) получает управление.Какое значение возвращает
Future
? Оно возвращает сам себя. Можете ли вы напрямую использовать yield
для Future
? Нет, это внутренняя деталь, о которой вам обычно не нужно беспокоиться.
class Awaitable:
def __await__(self):
future = asyncio.Future()
yield future
# RuntimeError: yield was used
# instead of yield from in task
async def coroutine():
await Awaitable()
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
Почему возникает эта ошибка? Как asyncio понимает, что это вы используете
yield
для Future
, а не сам Future
? Есть простая защита: Future
устанавливает внутренний флаг перед тем, как вернуть управление.👉@BookPython
Если вы хотите передать данные по цепочке вызовов, самый простой способ — использовать аргументы функций.
Однако в некоторых случаях модифицировать все функции в цепочке, чтобы передать новые данные, крайне неудобно. Вместо этого вы можете настроить некоторый контекст, который будет доступен для всех функций по цепочке. Как это можно реализовать технически?
Самое простое решение — глобальная переменная. В Python также можно использовать модули и классы как хранилища контекста, так как они, строго говоря, тоже являются глобальными переменными. Вы, вероятно, делаете это ежедневно, например, для работы с логгерами.
Если ваше приложение многопоточное, обычная глобальная переменная не подойдет, так как она не является потокобезопасной. Одновременно может выполняться несколько цепочек вызовов, и каждая из них нуждается в собственном контексте. Модуль
Но оба этих подхода не подходят для асинхронных приложений, где функции не только вызываются, но и могут быть приостановлены с помощью
Решить эту проблему можно, если цикл событий будет устанавливать и восстанавливать контекст каждый раз, когда он возобновляет выполнение корутины. Модуль
👉@BookPython
Однако в некоторых случаях модифицировать все функции в цепочке, чтобы передать новые данные, крайне неудобно. Вместо этого вы можете настроить некоторый контекст, который будет доступен для всех функций по цепочке. Как это можно реализовать технически?
Самое простое решение — глобальная переменная. В Python также можно использовать модули и классы как хранилища контекста, так как они, строго говоря, тоже являются глобальными переменными. Вы, вероятно, делаете это ежедневно, например, для работы с логгерами.
Если ваше приложение многопоточное, обычная глобальная переменная не подойдет, так как она не является потокобезопасной. Одновременно может выполняться несколько цепочек вызовов, и каждая из них нуждается в собственном контексте. Модуль
threading
решает эту проблему с помощью объекта threading.local()
, который является потокобезопасным. Вы можете хранить данные, просто устанавливая атрибуты, например: threading.local().symbol = '@'
.Но оба этих подхода не подходят для асинхронных приложений, где функции не только вызываются, но и могут быть приостановлены с помощью
await
. Если корутина выполняет await
, цикл событий может переключиться на другую корутину из совершенно другой цепочки вызовов. Это приведет к некорректной работе, как в следующем примере:
import asyncio
import sys
global_symbol = '.'
async def indication(timeout):
while True:
print(global_symbol, end='')
sys.stdout.flush()
await asyncio.sleep(timeout)
async def sleep(t, indication_t, symbol='.'):
loop = asyncio.get_event_loop()
global global_symbol
global_symbol = symbol
loop.create_task(indication(indication_t))
await asyncio.sleep(t)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
sleep(1, 0.1, '0'),
sleep(1, 0.1, 'a'),
sleep(1, 0.1, 'b'),
sleep(1, 0.1, 'c'),
))
Решить эту проблему можно, если цикл событий будет устанавливать и восстанавливать контекст каждый раз, когда он возобновляет выполнение корутины. Модуль
aiotask_context
реализует это, изменяя способ создания задач с помощью loop.set_task_factory
. Пример рабочей версии:
import asyncio
import sys
import aiotask_context as context
async def indication(timeout):
while True:
print(context.get('symbol'), end='')
sys.stdout.flush()
await asyncio.sleep(timeout)
async def sleep(t, indication_t, symbol='.'):
loop = asyncio.get_event_loop()
context.set(key='symbol', value=symbol)
loop.create_task(indication(indication_t))
await asyncio.sleep(t)
loop = asyncio.get_event_loop()
loop.set_task_factory(context.task_factory)
loop.run_until_complete(asyncio.gather(
sleep(1, 0.1, '0'),
sleep(1, 0.1, 'a'),
sleep(1, 0.1, 'b'),
sleep(1, 0.1, 'c'),
))
👉@BookPython
Обе конструкции
Когда вы реализуете метод
PEP 525 позволяет делать то же самое с методом
👉@BookPython
for
и with
могут быть асинхронными. async with
использует магические методы __aenter__
и __aexit__
, а async for
— методы __aiter__
и __anext__
. Все они асинхронные, и внутри них можно использовать await
:
import asyncio
class Sleep:
def __init__(self, t):
self._t = t
async def __aenter__(self):
await asyncio.sleep(self._t / 2)
async def __aexit__(self, *args):
await asyncio.sleep(self._t / 2)
async def main():
async with Sleep(2):
print('*')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Когда вы реализуете метод
__iter__
, часто вместо написания итератора с методом __next__
используется оператор yield
, который делает метод __iter__
генератором:
class Bracketed:
def __init__(self, data):
self._data = data
def __iter__(self):
for x in self._data:
yield '({})'.format(x)
print(list(Bracketed([1, 2, 3])))
# ['(1)', '(2)', '(3)']
PEP 525 позволяет делать то же самое с методом
__aiter__
. Наличие операторов yield
и await
в теле функции делает её асинхронным генератором. В то время как await
используется для взаимодействия с циклом событий, yield
управляет работой с for
:
import asyncio
class Slow:
def __init__(self, data, t=1):
self._data = data
self._t = t
async def __aiter__(self):
for x in self._data:
await asyncio.sleep(self._t)
yield x
async def main():
async for x in Slow([1, 2, 3]):
print(x)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
👉@BookPython
Рассмотрим следующую иерархию классов:
В каком порядке будет производиться поиск метода
Чтобы исправить эту проблему, Python использует линеаризацию C3 (C3 superclass linearization), алгоритм, который всегда ищет метод сначала во всех дочерних классах, а затем уже в родительских.
Пример вывода MRO (Method Resolution Order):
👉@BookPython
class GrandParent:
pass
class Parent1(GrandParent):
pass
class Parent2(GrandParent):
pass
class Child(Parent1, Parent2):
pass
В каком порядке будет производиться поиск метода
Child.x()
? Наивный подход заключается в рекурсивном поиске через все родительские классы, что даст порядок: Child
, Parent1
, GrandParent
, Parent2
. Такой метод используется во многих языках программирования, однако он не совсем логичен, так как Parent2
более специфичен, чем GrandParent
, и его нужно проверять раньше.Чтобы исправить эту проблему, Python использует линеаризацию C3 (C3 superclass linearization), алгоритм, который всегда ищет метод сначала во всех дочерних классах, а затем уже в родительских.
Пример вывода MRO (Method Resolution Order):
In : Child.__mro__
Out:
(__main__.Child,
__main__.Parent1,
__main__.Parent2,
__main__.GrandParent,
object)
👉@BookPython
Прямой доступ к атрибутам объекта может быть не самой лучшей идеей. Если клиенты взаимодействуют с объектом через методы, вы всегда можете изменить способ обработки каждого запроса, в то время как при прямом доступе к атрибутам это может быть невозможно.
Разные языки решают эту проблему по-разному. В Ruby синтаксически невозможно получить прямой доступ к атрибуту:
Python предлагает решение, которое в некотором роде похоже на то, что есть в Ruby. Вы можете определить свойство (`property`), чтобы
👉@BookPython
Разные языки решают эту проблему по-разному. В Ruby синтаксически невозможно получить прямой доступ к атрибуту:
obj.x
— это вызов метода x
. В Java рекомендуется делать все атрибуты приватными и писать тривиальные геттеры, например: public int getX() { return this.x; }
.Python предлагает решение, которое в некотором роде похоже на то, что есть в Ruby. Вы можете определить свойство (`property`), чтобы
obj.x
вызывал метод вместо прямого возврата атрибута x
.
class Example:
def __init__(self, x):
self._x = x
@property
def x(self):
return self._x
👉@BookPython
С версии Python 3.0 выбрасывание исключения внутри блока
Результат выполнения:
Вы также можете добавить
Результат выполнения:
👉@BookPython
except
автоматически добавляет перехваченное исключение в атрибут __context__
нового исключения. Это приводит к тому, что оба исключения отображаются в traceback:
try:
1 / 0
except ZeroDivisionError:
raise ValueError('Zero!')
Результат выполнения:
Traceback (most recent call last):
File "test.py", line 2, in <module>
1 / 0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 4, in <module>
raise ValueError('Zero!')
ValueError: Zero!
Вы также можете добавить
__cause__
к любому исключению с помощью выражения raise ... from
:
division_error = None
try:
1 / 0
except ZeroDivisionError as e:
division_error = e
raise ValueError('Zero!') from division_error
Результат выполнения:
Traceback (most recent call last):
File "test.py", line 4, in <module>
1 / 0
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "test.py", line 8, in <module>
raise ValueError('Zero!') from division_error
ValueError: Zero!
👉@BookPython
В Python множества поддерживают операторы сравнения, где
Это означает, что множества частично упорядочены, то есть существуют такие
Некоторые функции, такие как
👉@BookPython
a < b
означает, что a
является подмножеством b
:
>>> {1} < {1, 2}
True
>>> {1} < {2, 3}
False
Это означает, что множества частично упорядочены, то есть существуют такие
a
и b
, что и a < b
, и b < a
— ложны:
>>> {1} < {2, 3}
False
>>> {1} > {2, 3}
False
Некоторые функции, такие как
min
, max
и sorted
, требуют полного порядка, поэтому их применение к списку множеств может дать неожиданные результаты:
>>> min([{1}, {2}])
{1}
>>> min([{2}, {1}])
{2}
👉@BookPython
Иногда вам нужно очистить коллекцию в Python. Вы, вероятно, используете что-то вроде
Правильный способ очистки словаря, множества,
👉@BookPython
d = {}
(для словарей), но на самом деле это не очистка, а создание новой коллекции и выбрасывание старой. Это может сработать для вас, но другие владельцы того же объекта всё ещё будут иметь ссылку на оригинальный.Правильный способ очистки словаря, множества,
deque
и других коллекций — вызвать x.clear()
. 👉@BookPython
Подборка Telegram каналов для программистов
Системное администрирование 📌
https://t.me/sysadmin_girl Девочка Сисадмин
https://t.me/srv_admin_linux Админские угодья
https://t.me/linux_srv Типичный Сисадмин
https://t.me/linux_odmin Linux: Системный администратор
https://t.me/devops_star DevOps Star (Звезда Девопса)
https://t.me/i_linux Системный администратор
https://t.me/linuxchmod Linux
https://t.me/sys_adminos Системный Администратор
https://t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
https://t.me/sysadminof Книги для админов, полезные материалы
https://t.me/i_odmin Все для системного администратора
https://t.me/i_odmin_book Библиотека Системного Администратора
https://t.me/i_odmin_chat Чат системных администраторов
https://t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
https://t.me/sysadminoff Новости Линукс Linux
1C разработка 📌
https://t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://t.me/cpp_lib Библиотека C/C++ разработчика
https://t.me/cpp_knigi Книги для программистов C/C++
https://t.me/cpp_geek Учим C/C++ на примерах
Программирование Python 📌
https://t.me/pythonofff Python академия. Учи Python быстро и легко🐍
https://t.me/BookPython Библиотека Python разработчика
https://t.me/python_real Python подборки на русском и английском
https://t.me/python_360 Книги по Python Rus
Java разработка 📌
https://t.me/BookJava Библиотека Java разработчика
https://t.me/java_360 Книги по Java Rus
https://t.me/java_geek Учим Java на примерах
GitHub Сообщество 📌
https://t.me/Githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://t.me/database_info Все про базы данных
Мобильная разработка: iOS, Android 📌
https://t.me/developer_mobila Мобильная разработка
https://t.me/kotlin_lib Подборки полезного материала по Kotlin
Фронтенд разработка 📌
https://t.me/frontend_1 Подборки для frontend разработчиков
https://t.me/frontend_sovet Frontend советы, примеры и практика!
https://t.me/React_lib Подборки по React js и все что с ним связано
Разработка игр 📌
https://t.me/game_devv Все о разработке игр
Библиотеки 📌
https://t.me/book_for_dev Книги для программистов Rus
https://t.me/programmist_of Книги по программированию
https://t.me/proglb Библиотека программиста
https://t.me/bfbook Книги для программистов
https://t.me/books_reserv Книги для программистов
БигДата, машинное обучение 📌
https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning
Программирование 📌
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://t.me/coddy_academy Полезные советы по программированию
https://t.me/rust_lib Полезный контент по программированию на Rust
https://t.me/golang_lib Библиотека Go (Golang) разработчика
https://t.me/itmozg Программисты, дизайнеры, новости из мира IT
https://t.me/php_lib Библиотека PHP программиста 👨🏼💻👩💻
https://t.me/nodejs_lib Подборки по Node js и все что с ним связано
https://t.me/ruby_lib Библиотека Ruby программиста
QA, тестирование 📌
https://t.me/testlab_qa Библиотека тестировщика
Шутки программистов 📌
https://t.me/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://t.me/thehaking Канал о кибербезопасности
https://t.me/xakep_1 Статьи из "Хакера"
Книги, статьи для дизайнеров 📌
https://t.me/ux_web Статьи, книги для дизайнеров
Английский 📌
https://t.me/UchuEnglish Английский с нуля
Математика 📌
https://t.me/Pomatematike Канал по математике
https://t.me/phis_mat Обучающие видео, книги по Физике и Математике
Excel лайфхак📌
https://t.me/Excel_lifehack
https://t.me/tikon_1 Новости высоких технологий, науки и техники💡
https://t.me/mir_teh Мир технологий (Technology World)
Вакансии 📌
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
Системное администрирование 📌
https://t.me/sysadmin_girl Девочка Сисадмин
https://t.me/srv_admin_linux Админские угодья
https://t.me/linux_srv Типичный Сисадмин
https://t.me/linux_odmin Linux: Системный администратор
https://t.me/devops_star DevOps Star (Звезда Девопса)
https://t.me/i_linux Системный администратор
https://t.me/linuxchmod Linux
https://t.me/sys_adminos Системный Администратор
https://t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
https://t.me/sysadminof Книги для админов, полезные материалы
https://t.me/i_odmin Все для системного администратора
https://t.me/i_odmin_book Библиотека Системного Администратора
https://t.me/i_odmin_chat Чат системных администраторов
https://t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
https://t.me/sysadminoff Новости Линукс Linux
1C разработка 📌
https://t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://t.me/cpp_lib Библиотека C/C++ разработчика
https://t.me/cpp_knigi Книги для программистов C/C++
https://t.me/cpp_geek Учим C/C++ на примерах
Программирование Python 📌
https://t.me/pythonofff Python академия. Учи Python быстро и легко🐍
https://t.me/BookPython Библиотека Python разработчика
https://t.me/python_real Python подборки на русском и английском
https://t.me/python_360 Книги по Python Rus
Java разработка 📌
https://t.me/BookJava Библиотека Java разработчика
https://t.me/java_360 Книги по Java Rus
https://t.me/java_geek Учим Java на примерах
GitHub Сообщество 📌
https://t.me/Githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://t.me/database_info Все про базы данных
Мобильная разработка: iOS, Android 📌
https://t.me/developer_mobila Мобильная разработка
https://t.me/kotlin_lib Подборки полезного материала по Kotlin
Фронтенд разработка 📌
https://t.me/frontend_1 Подборки для frontend разработчиков
https://t.me/frontend_sovet Frontend советы, примеры и практика!
https://t.me/React_lib Подборки по React js и все что с ним связано
Разработка игр 📌
https://t.me/game_devv Все о разработке игр
Библиотеки 📌
https://t.me/book_for_dev Книги для программистов Rus
https://t.me/programmist_of Книги по программированию
https://t.me/proglb Библиотека программиста
https://t.me/bfbook Книги для программистов
https://t.me/books_reserv Книги для программистов
БигДата, машинное обучение 📌
https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning
Программирование 📌
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://t.me/coddy_academy Полезные советы по программированию
https://t.me/rust_lib Полезный контент по программированию на Rust
https://t.me/golang_lib Библиотека Go (Golang) разработчика
https://t.me/itmozg Программисты, дизайнеры, новости из мира IT
https://t.me/php_lib Библиотека PHP программиста 👨🏼💻👩💻
https://t.me/nodejs_lib Подборки по Node js и все что с ним связано
https://t.me/ruby_lib Библиотека Ruby программиста
QA, тестирование 📌
https://t.me/testlab_qa Библиотека тестировщика
Шутки программистов 📌
https://t.me/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://t.me/thehaking Канал о кибербезопасности
https://t.me/xakep_1 Статьи из "Хакера"
Книги, статьи для дизайнеров 📌
https://t.me/ux_web Статьи, книги для дизайнеров
Английский 📌
https://t.me/UchuEnglish Английский с нуля
Математика 📌
https://t.me/Pomatematike Канал по математике
https://t.me/phis_mat Обучающие видео, книги по Физике и Математике
Excel лайфхак📌
https://t.me/Excel_lifehack
https://t.me/tikon_1 Новости высоких технологий, науки и техники💡
https://t.me/mir_teh Мир технологий (Technology World)
Вакансии 📌
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
Иногда вам может понадобиться проверить синтаксис Python-файла без его запуска. Такая простая проверка может быть полезна, например, в качестве хука перед коммитом или быстрой проверки в рамках непрерывной интеграции (CI).
Прямого способа сделать это нет. Вы можете запустить файл с помощью команды
Тем не менее, стандартная библиотека Python содержит модуль
👉@BookPython
Прямого способа сделать это нет. Вы можете запустить файл с помощью команды
python -m module.py
, что предотвратит выполнение блока if __name__ == '__main__'
. Однако все импорты всё равно будут выполнены, и это может привести к ошибкам, если вы хотите проверить синтаксис в среде, где модуль не может и не должен быть запущен.Тем не менее, стандартная библиотека Python содержит модуль
py_compile
, который генерирует байт-код из исходного файла Python без его выполнения. Это именно то, что нам нужно:
$ python -m py_compile test.c
File "test.c", line 1
int main() {
^
SyntaxError: invalid syntax
👉@BookPython
CPython поддерживает два уровня оптимизации. Вы можете включить их с помощью флагов
- Флаг
- Флаг
Обычная версия скрипта кэшируется в файл
👉@BookPython
-O
и -OO
.- Флаг
-O
устанавливает __debug__
в значение False
и удаляет все операторы assert
из программы. - Флаг
-OO
делает то же самое, а также удаляет строки документации (docstrings).Обычная версия скрипта кэшируется в файл
.pyc
, а оптимизированная версия раньше кэшировалась в файл .pyo
. Однако, начиная с Python 3.5, файлы .pyo
больше не используются. Вместо них, в соответствии с PEP 488, вводятся файлы .opt-1.pyc
и .opt-2.pyc
.👉@BookPython
«Reduce» — это функция высшего порядка, которая рекурсивно обрабатывает итерируемый объект, применяя некоторую операцию к следующему элементу и уже вычисленному значению. Также вы можете знать её под названиями «fold», «inject», «accumulate» или другими.
Использование
В Python функция
Также, если вам нужны простые лямбда-функции, такие как
👉@BookPython
Использование
reduce
с result = result + element
даёт сумму всех элементов, result = min(result, element)
возвращает минимум, а result = element
позволяет получить последний элемент последовательности.В Python функция
reduce
доступна (начиная с Python 3, она была перемещена в functools.reduce
):
from functools import reduce
print(reduce(lambda s, i: s + i, range(10))) # 45
print(reduce(lambda s, i: min(s, i), range(10))) # 0
print(reduce(lambda s, i: i, range(10))) # 9
Также, если вам нужны простые лямбда-функции, такие как
lambda a, b: a + b
, в Python есть модуль operator
, который упрощает их использование:
from operator import add
print(reduce(add, range(10))) # 45
👉@BookPython
Чтобы отсортировать последовательность в Python, используйте
С помощью аргумента
Допустим, нам также нужно, чтобы числа с одинаковым абсолютным значением были расположены в порядке возрастания. В этом случае можно передать кортеж в качестве ключа сравнения:
Это не магия сортировки, а стандартное поведение кортежей в Python:
👉@BookPython
sorted
:
In : sorted([1, -1, 2, -3, 3])
Out: [-3, -1, 1, 2, 3]
С помощью аргумента
key
можно передать функцию, которая будет использоваться для получения ключа сравнения для каждого значения. Например, отсортируем ту же последовательность по абсолютным значениям:
In : sorted([1, -1, 2, -3, 3], key=abs)
Out: [1, -1, 2, -3, 3]
Допустим, нам также нужно, чтобы числа с одинаковым абсолютным значением были расположены в порядке возрастания. В этом случае можно передать кортеж в качестве ключа сравнения:
In : sorted([1, -1, 2, -3, 3], key=lambda x: (abs(x), x))
Out: [-1, 1, 2, -3, 3]
Это не магия сортировки, а стандартное поведение кортежей в Python:
In : (1, 2) == (1, 2)
Out: True
In : (1, 2) > (1, 1)
Out: True
In : (1, 2) < (2, 1)
Out: True
👉@BookPython
Создание новой переменной в Python фактически означает создание нового имени для уже существующего объекта. Именно поэтому этот процесс называется связыванием имени (name binding).
Существует множество способов связать имя с объектом. Вот примеры того, как можно связать
Также можно привязать имя к объекту, манипулируя глобальным пространством имен:
Однако нельзя сделать то же самое с
👉@BookPython
Существует множество способов связать имя с объектом. Вот примеры того, как можно связать
x
:
x = y # Присваивание
import x # Импорт модуля
class x: pass # Определение класса
def x(): pass # Определение функции
def y(x): pass # Определение аргумента функции
for x in y: pass # Перебор элементов в цикле
with y as x: pass # Использование в конструкции with
except y as x: pass # Обработка исключения
Также можно привязать имя к объекту, манипулируя глобальным пространством имен:
In : x
NameError: name 'x' is not defined # Ошибка: переменная x не определена
In : globals()['x'] = 42 # Присваивание через globals()
In : x
Out: 42 # Теперь x привязан к 42
Однако нельзя сделать то же самое с
locals()
, так как изменения словаря locals()
игнорируются.👉@BookPython
Когда в Python используется переменная, сначала она ищется в текущей области видимости. Если такая переменная не найдена, поиск продолжается во вложенной области. Это повторяется до тех пор, пока не будет достигнуто глобальное пространство имен.
Однако присваивание переменной работает иначе. Новая переменная всегда создается в текущей области видимости, если не указано
👉@BookPython
x = 1
def scope():
x = 2
def inner_scope():
print(x) # выводит 2
inner_scope()
scope()
Однако присваивание переменной работает иначе. Новая переменная всегда создается в текущей области видимости, если не указано
global
или nonlocal
:
x = 1
def scope():
x = 2
def inner_scope():
x = 3
print(x) # выводит 3
inner_scope()
print(x) # выводит 2
scope()
print(x) # выводит 1
global
позволяет использовать переменные из глобального пространства имен, а nonlocal
ищет переменную в ближайшей окружающей области видимости. Сравните:
x = 1
def scope():
x = 2
def inner_scope():
global x
x = 3
print(x) # выводит 3
inner_scope()
print(x) # выводит 2
scope()
print(x) # выводит 3
x = 1
def scope():
x = 2
def inner_scope():
nonlocal x
x = 3
print(x) # выводит 3
inner_scope()
print(x) # выводит 3
scope()
print(x) # выводит 1
👉@BookPython
list
позволяет хранить массив из любых объектов. Это довольно удобно, но может быть неэффективно. Для компактного представления массивов базовых значений можно использовать модуль array
. Поддерживаемые значения включают различные типы C, такие как char
, int
, long
, double
и другие. Фактическое представление определяется реализацией C.
import array
a = array.array('B') # Создаем массив байтов
a.append(240)
a.append(159)
a.append(144)
a.append(180)
print(a.tobytes().decode('utf8')) # Выводит: '🐴'
👉@BookPython
Если вам нужно итерироваться по нескольким итерируемым объектам одновременно, функция
Обратите внимание, что
Для распаковки значений можно использовать оператор
👉@BookPython
zip
может быть хорошим выбором. Она возвращает генератор, который выдаёт кортежи, содержащие по одному элементу из каждого исходного итерируемого объекта:
In : eng = ['one', 'two', 'three']
In : ger = ['eins', 'zwei', 'drei']
In : for e, g in zip(eng, ger):
...: print('{e} = {g}'.format(e=e, g=g))
...:
one = eins
two = zwei
three = drei
Обратите внимание, что
zip
принимает итерируемые объекты как отдельные аргументы, а не список аргументов. Для распаковки значений можно использовать оператор
*
:
In : list(zip(*zip(eng, ger)))
Out: [('one', 'two', 'three'), ('eins', 'zwei', 'drei')]
👉@BookPython
Модуль
Эти два типа —
👉@BookPython
io
предоставляет два типа файловых объектов в памяти. Такие объекты могут быть полезны для работы с интерфейсами, которые поддерживают только файлы, без необходимости создавать их на диске. Очевидный пример — модульное тестирование.Эти два типа —
BytesIO
и StringIO
, которые работают соответственно с байтами и строками.
from io import StringIO
f = StringIO()
f.write('first\n') # Вывод: 6
f.write('second\n') # Вывод: 7
f.seek(0) # Вывод: 0
print(f.readline()) # Вывод: 'first\n'
print(f.readline()) # Вывод: 'second\n'
👉@BookPython
Python поддерживает несколько способов запуска скрипта. Обычный вариант — это
Однако, можно также использовать
Можно также запустить Python с каталогом:
Пример:
👉@BookPython
python foo.py
; в этом случае foo.py
просто выполняется.Однако, можно также использовать
python -m foo
. Если foo
— это не пакет, то foo.py
ищется в sys.path
и выполняется. Если это пакет, то Python сначала выполняет foo/__init__.py
, а затем foo/__main__.py
. Обратите внимание, что во время выполнения __init__.py
значение __name__
равно foo
, но во время выполнения __main__.py
оно равно __main__
.Можно также запустить Python с каталогом:
python dir/
или даже python dir.zip
. В этом случае Python ищет dir/__main__.py
и выполняет его, если находит.Пример:
$ ls foo
__init__.py __main__.py
$ cat foo/__init__.py
print(__name__)
$ cat foo/__main__.py
print(__name__)
$ python -m foo
foo
__main__
$ python foo/
__main__
$ python foo/__init__.py
__main__
👉@BookPython