Чтобы сохранить любую информацию в памяти или на устройстве хранения, её необходимо представить в виде байтов. Python, как правило, предоставляет уровень абстракции, при котором вы оперируете непосредственно данными, а не их байтовым представлением.
Тем не менее, когда вы, скажем, записываете строку в файл, вы работаете с физической структурой данных. Чтобы поместить символы в файл, их нужно преобразовать в байты — это называется кодированием. Когда вы получаете байты из файла, скорее всего, вы захотите превратить их в осмысленные символы — это называется декодированием.
Существует сотни методов кодирования. Самый популярный — вероятно, Unicode, но он сам по себе не может преобразовывать данные в байты. В смысле байтового представления Unicode вообще не является кодировкой. Unicode определяет соответствие между символами и их числовыми кодами. Например, 🐍 имеет код 128013.
Но чтобы записать числа в файл, нужна настоящая кодировка. Unicode обычно используется вместе с utf-8, которая (в большинстве случаев) является стандартной в Python. При чтении из файла Python автоматически декодирует utf-8. Вы можете выбрать любую другую кодировку с помощью параметра
📲 Мы в MAX
👉@BookPython
Тем не менее, когда вы, скажем, записываете строку в файл, вы работаете с физической структурой данных. Чтобы поместить символы в файл, их нужно преобразовать в байты — это называется кодированием. Когда вы получаете байты из файла, скорее всего, вы захотите превратить их в осмысленные символы — это называется декодированием.
Существует сотни методов кодирования. Самый популярный — вероятно, Unicode, но он сам по себе не может преобразовывать данные в байты. В смысле байтового представления Unicode вообще не является кодировкой. Unicode определяет соответствие между символами и их числовыми кодами. Например, 🐍 имеет код 128013.
Но чтобы записать числа в файл, нужна настоящая кодировка. Unicode обычно используется вместе с utf-8, которая (в большинстве случаев) является стандартной в Python. При чтении из файла Python автоматически декодирует utf-8. Вы можете выбрать любую другую кодировку с помощью параметра
encoding= функции open, либо читать «сырые» байты, добавив b к режиму открытия файла.📲 Мы в MAX
👉@BookPython
Если вы создаёте новые объекты внутри метода
В этом примере
Возможный рефакторинг:
Такой подход имеет как минимум следующие преимущества:
• Упрощает внедрение зависимостей. В тестах можно использовать
• Класс может иметь столько фабричных методов, сколько нужно; подключение может создаваться не только по
• Такие фабричные методы можно сделать асинхронными; это невозможно для
📲 Мы в MAX
👉@BookPython
__init__, возможно, будет лучше передавать их как аргументы и использовать фабричный метод. Это позволяет разделить бизнес-логику и технические детали создания объектов.В этом примере
__init__ принимает host и port для создания подключения к базе данных:
class Query:
def __init__(self, host, port):
self._connection = Connection(host, port)
Возможный рефакторинг:
class Query:
def __init__(self, connection):
self._connection = connection
@classmethod
def create(cls, host, port):
return cls(Connection(host, port))
Такой подход имеет как минимум следующие преимущества:
• Упрощает внедрение зависимостей. В тестах можно использовать
Query(FakeConnection()).• Класс может иметь столько фабричных методов, сколько нужно; подключение может создаваться не только по
host и port, но и путём клонирования другого подключения, чтения конфигурационного файла или объекта, использования значения по умолчанию и т.д.• Такие фабричные методы можно сделать асинхронными; это невозможно для
__init__.📲 Мы в MAX
👉@BookPython
👍5
🚀 Подборка полезных IT каналов в Max
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
https://max.ru/tipsysdmin Типичный Сисадмин
https://max.ru/channel_win_sysadmin Системный Администратор Windows
https://max.ru/channel_linux_admin Linux: Системный администратор
https://max.ru/channel_linuxmod Linux
https://max.ru/channel_i_linux Системный администратор
https://max.ru/channel_devopslib DevOps, SRE, Sysadmin
https://max.ru/channel_devops_star DevOps Star (Звезда Девопса)
Excel лайфхак 📌
https://t.me/Excel_lifehack Excel лайфхак
Английский с нуля 🇬🇧
https://max.ru/UchuEnglish
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://max.ru/channel_DevLab1C 1С:Предприятие 8
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
https://max.ru/channel_cpp_geek C++ geek
Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика
Программирование React📌
https://max.ru/react_lib React
Программирование Rust📌
https://max.ru/channel_rust_lib
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
https://max.ru/channel_java_geek Java Geek
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии в IT📌
https://max.ru/progjob
https://max.ru/channel_rabotait
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Городские📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
https://max.ru/channel_krasnodar_novosty Краснодар Новости
https://max.ru/channel_novosibirsk_novosti Новосибирск
https://max.ru/channel_samara_novosti Новости Самары
https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга
https://max.ru/channel_kazan_novosti Новости Казани
https://max.ru/channel_omsk_novosti Новости Омска
https://max.ru/channel_moskva_24 Москва 24
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
https://max.ru/tipsysdmin Типичный Сисадмин
https://max.ru/channel_win_sysadmin Системный Администратор Windows
https://max.ru/channel_linux_admin Linux: Системный администратор
https://max.ru/channel_linuxmod Linux
https://max.ru/channel_i_linux Системный администратор
https://max.ru/channel_devopslib DevOps, SRE, Sysadmin
https://max.ru/channel_devops_star DevOps Star (Звезда Девопса)
Excel лайфхак 📌
https://t.me/Excel_lifehack Excel лайфхак
Английский с нуля 🇬🇧
https://max.ru/UchuEnglish
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://max.ru/channel_DevLab1C 1С:Предприятие 8
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
https://max.ru/channel_cpp_geek C++ geek
Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика
Программирование React📌
https://max.ru/react_lib React
Программирование Rust📌
https://max.ru/channel_rust_lib
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
https://max.ru/channel_java_geek Java Geek
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии в IT📌
https://max.ru/progjob
https://max.ru/channel_rabotait
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Городские📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
https://max.ru/channel_krasnodar_novosty Краснодар Новости
https://max.ru/channel_novosibirsk_novosti Новосибирск
https://max.ru/channel_samara_novosti Новости Самары
https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга
https://max.ru/channel_kazan_novosti Новости Казани
https://max.ru/channel_omsk_novosti Новости Омска
https://max.ru/channel_moskva_24 Москва 24
MAX
Системный Администратор | Sysadmin Windows & Linux Server. …
Реклама Tg t.me/evgenycarter
Купить рекламу: https://telega.in/m/i_odmin
Блог практикующего админа. Настройка Windows Server, Active Directory (AD), GPO и те…
Купить рекламу: https://telega.in/m/i_odmin
Блог практикующего админа. Настройка Windows Server, Active Directory (AD), GPO и те…
Обычно вы взаимодействуете с генератором, запрашивая данные с помощью
С помощью
Эта техника позволяет более точно управлять поведением генератора — не только передавать данные внутрь, но и, например, сообщать о проблемах со значениями, полученными через
Тем не менее, декоратор
📲 Мы в MAX
👉@BookPython
next(gen). В Python 3 вы также можете отправлять значения обратно в генератор с помощью g.send(x). Но существует техника, которой вы, вероятно, не пользуетесь каждый день, а возможно, и вовсе не знаете: выбрасывание исключений внутри генератора.С помощью
gen.throw(e) можно выбросить исключение в той точке, где генератор gen приостановлен — то есть на инструкции yield. Если генератор обрабатывает это исключение, gen.throw(e) возвращает следующее значение, полученное через yield (или выбрасывает StopIteration, если генератор завершён). Если генератор не перехватывает исключение, оно пробрасывается обратно к вызывающему коду.
def gen():
try:
yield 1
except ValueError:
yield 2
g = gen()
next(g)
# Out: 1
g.throw(ValueError)
# Out: 2
g.throw(RuntimeError('TEST'))
# RuntimeError: TEST
Эта техника позволяет более точно управлять поведением генератора — не только передавать данные внутрь, но и, например, сообщать о проблемах со значениями, полученными через
yield. Однако такие случаи бывают редко, и встретить g.throw в дикой природе почти невозможно.Тем не менее, декоратор
@contextmanager из модуля contextlib использует именно такую технику, позволяя коду внутри контекста перехватывать исключения.
from contextlib import contextmanager
@contextmanager
def atomic():
print('BEGIN')
try:
yield
except Exception:
print('ROLLBACK')
else:
print('COMMIT')
with atomic():
print('ERROR')
raise RuntimeError()
BEGIN
ERROR
ROLLBACK
📲 Мы в MAX
👉@BookPython
👍3
Стандартный механизм расширения путей в оболочке называется globbing. Шаблоны, которые вы используете для сопоставления путей, называются globs.
Python поддерживает globbing с помощью модуля
📲 Мы в MAX
👉@BookPython
$ echo /li*
/lib /lib64
Python поддерживает globbing с помощью модуля
glob. Однако есть важное замечание: оболочка возвращает сам шаблон, если файлы не найдены, а Python — нет:
$ echo /zz**
/zz**
$ python -c 'from glob import glob; print(glob("/zz**"))'
[]
📲 Мы в MAX
👉@BookPython
👍3❤1🔥1
Функция
Имя функции
Пример:
Обрати внимание: результат работы
📲 Мы в MAX
👉@BookPython
super() позволяет обращаться к родительскому (базовому) классу. Это может быть очень полезно в случаях, когда производный класс хочет добавить что-то к реализации метода, а не полностью переопределять его:
class BaseTestCase(TestCase):
def setUp(self):
self._db = create_db()
class UserTestCase(BaseTestCase):
def setUp(self):
super().setUp()
self._user = create_user()
Имя функции
super не означает "отличный" или "очень хороший". В данном контексте слово super означает "выше" (как, например, в слове superintendent — заведующий). Несмотря на это, super() не всегда ссылается на базовый класс — он может вернуть и "соседний" класс. Более точным названием была бы, возможно, функция next(), так как возвращается следующий класс согласно цепочке разрешения методов (MRO — Method Resolution Order).Пример:
class Top:
def foo(self):
return 'top'
class Left(Top):
def foo(self):
return super().foo()
class Right(Top):
def foo(self):
return 'right'
class Bottom(Left, Right):
pass
# выводит 'right'
print(Bottom().foo())
Обрати внимание: результат работы
super() может отличаться в зависимости от MRO вызвавшего объекта.
>>> Bottom().foo()
'right'
>>> Left().foo()
'top'
👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1🔥1
Функция
Однако если каждый элемент итерируемого объекта — это кортеж, было бы удобно передавать каждый элемент кортежа как отдельный аргумент. В Python 2 это было возможно благодаря распаковке параметров кортежа (обратите внимание на скобки):
В Python 3 эта возможность исчезла, но есть другое решение —
📲 Мы в MAX
👉@BookPython
map вызывает другую функцию для каждого элемента итерируемого объекта. Это значит, что функция должна принимать одно значение в качестве аргумента:
In : list(map(lambda x: x ** 2, [1, 2, 3]))
Out: [1, 4, 9]
Однако если каждый элемент итерируемого объекта — это кортеж, было бы удобно передавать каждый элемент кортежа как отдельный аргумент. В Python 2 это было возможно благодаря распаковке параметров кортежа (обратите внимание на скобки):
>>> map(lambda (a, b): a + b, [(1, 2), (3, 4)])
[3, 7]
В Python 3 эта возможность исчезла, но есть другое решение —
itertools.starmap. Она распаковывает кортежи за вас, будто функция вызывается со звёздочкой: f(*arg) (отсюда и название функции):
from itertools import starmap
In [3]: list(starmap(lambda a, b: a + b, [(1, 2), (3, 4)]))
Out[3]: [3, 7]
👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Когда вы используете модуль
Однако сериализация исключений может быть непростой задачей. Исключение создаётся с любым количеством аргументов, которые сохраняются в атрибуте
Но это может не сработать так, как вы ожидаете, особенно если используется наследование. Посмотрите на пример:
Вызов
Обходное решение — либо вообще не вызывать
📲 Мы в MAX
👉@BookPython
multiprocessing, и в одном из процессов происходит исключение, оно передаётся в основную программу с помощью механизма сериализации (pickling). Исключение сериализуется, передаётся в другой процесс и там десериализуется обратно.Однако сериализация исключений может быть непростой задачей. Исключение создаётся с любым количеством аргументов, которые сохраняются в атрибуте
args. Эти же аргументы используются при десериализации для воссоздания объекта исключения.Но это может не сработать так, как вы ожидаете, особенно если используется наследование. Посмотрите на пример:
import pickle
class TooMuchWeightError(Exception):
def __init__(self, weight):
super().__init__()
self._weight = weight
pickled = pickle.dumps(TooMuchWeightError(42))
pickle.loads(pickled)
Вызов
TooMuchWeightError.__init__ приводит к вызову Exception.__init__, который устанавливает args как пустой кортеж. Этот пустой кортеж затем используется в качестве аргументов при десериализации, что, очевидно, приводит к ошибке:
TypeError: __init__() missing 1 required positional argument: 'weight'
Обходное решение — либо вообще не вызывать
super().__init__() (что обычно считается плохой практикой при наследовании), либо передавать все аргументы явно в конструктор родительского класса:
class TooMuchWeightError(Exception):
def __init__(self, weight):
super().__init__(weight)
self._weight = weight
👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
yield from — элегантная передача управленияЕсли вы пишете генераторы, которые вызывают другие генераторы — забудьте про
for x in sub(): yield x. Есть способ проще и мощнее.Оператор
yield from позволяет передавать элементы из подгенератора напрямую, без лишнего кода. Но фишка не только в лаконичности — он также автоматически пробрасывает исключения и возвращаемые значения из подгенератора.Вот классика:
def gen():
for x in range(3):
yield x
def wrapper():
for x in gen():
yield x
Можно короче и лучше:
def wrapper():
yield from gen()
Но главное —
yield from пробрасывает return-значение из подгенератора (начиная с Python 3.3):
def sub():
yield 1
yield 2
return 'done'
def main():
result = yield from sub()
print('Sub returned:', result)
for _ in main():
pass
# Выведет: Sub returned: done
А ещё через
yield from можно проксировать значения внутрь генератора — например, в сопрограммах:
def delegator():
result = yield from coroutine()
print('coroutine done:', result)
def coroutine():
x = yield
y = yield
return x + y
g = delegator()
next(g) # Старт
next(g) # coroutine ждет x
g.send(10) # x = 10
print(g.send(20)) # y = 20 → return 30
# Выведет: coroutine done: 30
Итог: если вы пишете генераторы — освоение
yield from даст вам лаконичный синтаксис, проброс return-значений, исключений и взаимодействие на новом уровне.👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
default_factory в dataclass: мощнее, чем кажетсяМногие используют
dataclass как удобный способ задать структуру с полями. Но редко кто по-настоящему раскрывает силу default_factory. А зря — он спасает от багов и даёт гибкость.Когда нужно задать значение по умолчанию для поля в
dataclass, логично тянуться к default=. Но если это изменяемый тип (например, список или словарь) — вас поджидает ловушка.
from dataclasses import dataclass, field
@dataclass
class User:
name: str
tags: list[str] = [] # ⚠️ опасно!
Все экземпляры
User будут делить один и тот же список. То есть:
a = User("Alice")
b = User("Bob")
a.tags.append("admin")
print(b.tags) # ['admin'] 😱
Вместо этого используйте
default_factory:
@dataclass
class User:
name: str
tags: list[str] = field(default_factory=list)
Теперь у каждого
User будет свой список:
a = User("Alice")
b = User("Bob")
a.tags.append("admin")
print(b.tags) # []
Но
default_factory не только про списки. Это отличный способ задать любое значение "по умолчанию", включая кастомную логику:
import uuid
@dataclass
class Session:
id: str = field(default_factory=lambda: str(uuid.uuid4()))
Или, например, значения из окружения:
import os
@dataclass
class Config:
debug: bool = field(default_factory=lambda: os.getenv("DEBUG") == "1")
Кстати, это ещё и отличное место для внедрения DI:
@dataclass
class Service:
client: "Client" = field(default_factory=create_default_client)
default_factory — это маленький хак, который позволяет сделать код чище и безопаснее, особенно когда работаешь с изменяемыми структурами или сложной инициализацией.👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2
Скрытые фичи
Многие используют
Вот несколько приёмов, которые мало кто использует — но зря.
1. Добавление поведения в Enum
Теперь
2. Enum с полями
3. Автоматические значения с
Удобно, если не важны конкретные значения, а нужны уникальные.
4. Строгая сериализация
В реальных приложениях (API, базы) лучше контролировать сериализацию enum'ов:
5. Сравнение по значению
Итого:
📲 Мы в MAX
👉@BookPython
Enum: как выжать максимумМногие используют
Enum как простой список констант. Но у enum.Enum в Python есть куда больше возможностей — и они могут сделать код чище и мощнее.Вот несколько приёмов, которые мало кто использует — но зря.
1. Добавление поведения в Enum
from enum import Enum
class Status(Enum):
DRAFT = 'draft'
PUBLISHED = 'published'
ARCHIVED = 'archived'
def is_visible(self):
return self in {Status.DRAFT, Status.PUBLISHED}
Теперь
Status.DRAFT.is_visible() — это просто и элегантно.2. Enum с полями
from enum import Enum
class Color(Enum):
RED = ('#FF0000', 'danger')
GREEN = ('#00FF00', 'safe')
def __init__(self, hex_code, label):
self.hex_code = hex_code
self.label = label
Color.RED.hex_code # '#FF0000'
Color.RED.label # 'danger'
3. Автоматические значения с
auto()
from enum import Enum, auto
class Role(Enum):
ADMIN = auto()
USER = auto()
GUEST = auto()
Удобно, если не важны конкретные значения, а нужны уникальные.
4. Строгая сериализация
В реальных приложениях (API, базы) лучше контролировать сериализацию enum'ов:
import json
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Enum):
return obj.value
return super().default(obj)
json.dumps(Status.PUBLISHED, cls=CustomEncoder) # "published"
5. Сравнение по значению
Status('draft') == Status.DRAFT # True
Status('draft') is Status.DRAFT # True (enum гарантирует singleton)
Итого:
Enum — это не просто константы. Это лёгкий способ инкапсулировать поведение и данные, улучшить читаемость и сделать код устойчивее к ошибкам.👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1
Иногда в программе нужна очередь — контейнер, куда элементы добавляются с одной стороны и извлекаются с другой. В Python для этого можно использовать
Однако
Как видно, операция
Для очередей лучше использовать
📲 Мы в MAX
👉@BookPython
list:
In : lst = [1, 2, 3]
In : lst.pop()
Out: 3
In : lst
Out: [1, 2]
In : lst[:0] = [4] # push
In : lst
Out: [4, 1, 2]
Однако
list выглядит не очень удобно (взгляните на этот "push") и работает неэффективно.
In : lst = [0] * 10_000_000
In : %timeit lst[:0] = [1]
9.5 ms ± 111 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In : %timeit lst.pop()
84.3 ns ± 4.01 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Как видно, операция
pop() в 100 раз быстрее, чем вставка в начало списка. Это связано с тем, как устроен list в Python: легко добавлять и удалять элементы с конца, но удаление/добавление в начало требует создания нового списка.Для очередей лучше использовать
collections.deque. Он специально для этого создан:
In : from collections import deque
In : d = deque([1] * 100_000_000)
In : %timeit d.popleft()
65 ns ± 0.436 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Некоторый код может выводить интересующие вас данные в stdout, вместо того чтобы предоставлять API, возвращающий строку, пригодную для использования в программе.
Вместо рефакторинга такого кода можно воспользоваться менеджером контекста
Также существует
📲 Мы в MAX
👉@BookPython
Вместо рефакторинга такого кода можно воспользоваться менеджером контекста
contextlib.redirect_stdout, который позволяет временно перенаправить stdout в любой объект, поддерживающий файловый интерфейс. В сочетании с io.StringIO это позволяет сохранить вывод в переменную.
from contextlib import redirect_stdout
from io import StringIO
s = StringIO()
with redirect_stdout(s):
print(42)
print(s.getvalue())
Также существует
contextlib.redirect_stderr для перенаправления вывода sys.stderr.👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Популярный способ объявить абстрактный метод в Python — это выбросить исключение
Хотя этот подход довольно распространён и даже поддерживается IDE (например, PyCharm считает такие методы абстрактными), у него есть недостаток: ошибка возникает только при вызове метода, а не при создании экземпляра класса.
Чтобы избежать этой проблемы, используйте модуль
Также важно помнить, что
📲 Мы в MAX
👉@BookPython
NotImplementedError:
def human_name(self):
raise NotImplementedError
Хотя этот подход довольно распространён и даже поддерживается IDE (например, PyCharm считает такие методы абстрактными), у него есть недостаток: ошибка возникает только при вызове метода, а не при создании экземпляра класса.
Чтобы избежать этой проблемы, используйте модуль
abc:
from abc import ABCMeta, abstractmethod
class Service(metaclass=ABCMeta):
@abstractmethod
def human_name(self):
pass
Также важно помнить, что
NotImplemented — это не то же самое, что NotImplementedError. NotImplemented — это специальное значение (как True и False), а не исключение. Оно используется, например, в специальных методах (__eq__(), __add__() и др.), чтобы сообщить Python, что операция не реализована для данного типа, и попытаться вызвать альтернативный метод (например, если a.__add__(b) возвращает NotImplemented, Python попробует вызвать b.__radd__(a)).👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1