PYPROGLIB Telegram 6772
😡 How to: не писать `__init__`

До Python 3.7, если вы хотели создать объект Coordinate(x=1, y=2), приходилось писать:
class Coordinate:
def __init__(self, x: int, y: int):
self.x = x
self.y = y


Это выглядело нормально. Но:
📍 если убрать класс из API — теряется типизация;
📍 если разрешить создавать объект без данных — получаем некорректные объекты;
📍 если задать поля по умолчанию — объект становится мутируемым;
📍 для валидации нужно усложнять структуру.

Главная проблема

__init__ запускает код при каждом создании объекта, что усложняет работу, особенно если нужны побочные действия (например, открытие файла).

Пример проблемного кода:
class FileReader:
def __init__(self, path: str):
self._fd = fileio.open(path)


Вроде удобно. Но:
📍 Вы не можете передать fd напрямую — нужно городить object.__new__.
📍 Тестировать сложно — надо мокать fileio.open.
📍 Если open становится async, вам уже не обойтись __init__.

Ключевая ошибка: связывать создание объекта с побочными эффектами (например, I/O) — это антипаттерн.

Современное решение

1⃣ Используйте @dataclass для объявления:
@dataclass
class FileReader:
_fd: int # или лучше: FileDescriptor


2⃣ Вынесите создание объекта в @classmethod:
from typing import Self

@dataclass
class FileReader:
_fd: int

@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path))


Теперь создавайте объект так: FileReader.open("file.txt"), а не через __init__.

Это решение поддерживает:
📍 чистую типизацию
📍 возможность перехода на async
📍 множественные фабрики (from_fd, from_buffer, from_resource, ...)

3⃣ Типизируйте примитивы через NewType:
from typing import NewType
FileDescriptor = NewType("FileDescriptor", int)


Используйте в классе:
@dataclass
class FileReader:
_fd: FileDescriptor

@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path)) # пусть возвращает FileDescriptor


Новая практика для классов в Python:
1. Используйте @dataclass.
2. Не пишите __init__ вручную.
3. Добавляйте @classmethod-фабрики (.open(), .from_config(), .from_env()).
4. Используйте NewType.

Это даёт чистый, тестируемый, удобный и расширяемый код.

Библиотека питониста #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1713👍7🔥4🥱4🌚32👏1



tgoop.com/pyproglib/6772
Create:
Last Update:

😡 How to: не писать `__init__`

До Python 3.7, если вы хотели создать объект Coordinate(x=1, y=2), приходилось писать:

class Coordinate:
def __init__(self, x: int, y: int):
self.x = x
self.y = y


Это выглядело нормально. Но:
📍 если убрать класс из API — теряется типизация;
📍 если разрешить создавать объект без данных — получаем некорректные объекты;
📍 если задать поля по умолчанию — объект становится мутируемым;
📍 для валидации нужно усложнять структуру.

Главная проблема

__init__ запускает код при каждом создании объекта, что усложняет работу, особенно если нужны побочные действия (например, открытие файла).

Пример проблемного кода:
class FileReader:
def __init__(self, path: str):
self._fd = fileio.open(path)


Вроде удобно. Но:
📍 Вы не можете передать fd напрямую — нужно городить object.__new__.
📍 Тестировать сложно — надо мокать fileio.open.
📍 Если open становится async, вам уже не обойтись __init__.

Ключевая ошибка: связывать создание объекта с побочными эффектами (например, I/O) — это антипаттерн.

Современное решение

1⃣ Используйте @dataclass для объявления:
@dataclass
class FileReader:
_fd: int # или лучше: FileDescriptor


2⃣ Вынесите создание объекта в @classmethod:
from typing import Self

@dataclass
class FileReader:
_fd: int

@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path))


Теперь создавайте объект так: FileReader.open("file.txt"), а не через __init__.

Это решение поддерживает:
📍 чистую типизацию
📍 возможность перехода на async
📍 множественные фабрики (from_fd, from_buffer, from_resource, ...)

3⃣ Типизируйте примитивы через NewType:
from typing import NewType
FileDescriptor = NewType("FileDescriptor", int)


Используйте в классе:
@dataclass
class FileReader:
_fd: FileDescriptor

@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path)) # пусть возвращает FileDescriptor


Новая практика для классов в Python:
1. Используйте @dataclass.
2. Не пишите __init__ вручную.
3. Добавляйте @classmethod-фабрики (.open(), .from_config(), .from_env()).
4. Используйте NewType.

Это даёт чистый, тестируемый, удобный и расширяемый код.

Библиотека питониста #буст

BY Библиотека питониста | Python, Django, Flask




Share with your friend now:
tgoop.com/pyproglib/6772

View MORE
Open in Telegram


Telegram News

Date: |

In the “Bear Market Screaming Therapy Group” on Telegram, members are only allowed to post voice notes of themselves screaming. Anything else will result in an instant ban from the group, which currently has about 75 members. fire bomb molotov November 18 Dylan Hollingsworth yau ma tei Telegram iOS app: In the “Chats” tab, click the new message icon in the right upper corner. Select “New Channel.” Click “Save” ; More>>
from us


Telegram Библиотека питониста | Python, Django, Flask
FROM American