ホームページ >バックエンド開発 >Python チュートリアル >Python での入力の影響
Python バージョン 3.5 では、コードを読みやすくし、開発者がお互いのコードを理解しやすくするために「型ヒント」が導入されました。
Java や C などの強く型付けされた言語では、依存関係の反転 (DI - dependency Inversion) は重要な技術ですが、弱い型付けの言語では実装が困難です。
依存関係の逆転の中心となる考え方は、クラスは特定の実装ではなく抽象化に依存すべきであるということです。抽象化 (インターフェイスまたは抽象クラス) は比較的安定したコントラクトであるためです。
悪い例:
<code class="language-python">class GasStation: def fill_tank(car, amount): car.fill(amount)</code>
この例では、ガソリン スタンドは車に給油することしかできません。さらに悪いことに、関数 fill_tank
には型が定義されていないため、任意の値が渡される可能性があり、エラーは実行時にのみ発見されます。
良い例:
<code class="language-python">from typing import Protocol class Vehicle(Protocol): def fill(amount: int) -> None: ... class GasStation: def fill_tank(vehicle: Vehicle, amount: int) -> None: vehicle.fill(amount)</code>
この例では、最初に抽象クラス Vehicle
を定義します (typing.Protocol
を使用)。 GasStation
の fill_tank
機能は、特定の自動車クラスに依存するのではなく、Vehicle
インターフェースに依存するようになり、より一般化され、fill
メソッドを実装するあらゆる車両に燃料を補給できます。
私は Python の型ヒント システムを利用して、PyDIT (Python dependency Injection with Types) と呼ばれる依存関係反転の使用を簡素化するライブラリを作成しました。
ユーザー データを保存するためのデータベース インターフェイスが必要であるとします。PostgreSQL、MySQL、OracleDB、インメモリ データベース、NoSQL データベースのいずれを使用する場合でも、データベース接続クラスを実装し、レコードの読み取り、書き込み、削除の機能を提供する必要があります。 。
<code class="language-python">from time import sleep from typing import TypedDict from typing_extensions import override from uuid import UUID from src.configs.di import pydit from src.adapters.repositories.interfaces.user import UserRepository from src.constants.injection import MEMORY_REPOSITORY_CONFIG_TOKEN from src.domain.user.models.user import UserModel class ConfigType(TypedDict): delay: int class MemoryUserRepository(UserRepository): __users: dict[UUID, UserModel] = {} def __init__(self): self.__delay = self.config.get("delay", 0.2) @pydit.inject(token=MEMORY_REPOSITORY_CONFIG_TOKEN) def config(self) -> ConfigType: # TODO: supress return type error pass @override def get_by_id(self, *, id_: UUID) -> UserModel: sleep(self.__delay) user = self.__users.get(id_) if user is None: raise ValueError("User not found") return user @override def save(self, *, data: UserModel) -> None: sleep(self.__delay) self._check_pk_conflict(pk=data.id) self.__users[data.id] = data @override def list_(self) -> list[UserModel]: return list(self.__users.values()) def _check_pk_conflict(self, *, pk: UUID) -> None: if pk not in self.__users: return raise ValueError("Primary key conflicts: DB alrady has a user with this ID")</code>
コードがデータベース テクノロジと無関係であることを保証するために、すべてのデータベース クラスが従う必要があるインターフェイスを定義します。
<code class="language-python">from abc import abstractmethod from typing import Protocol from uuid import UUID from src.domain.user.models.user import UserModel class UserRepository(Protocol): @abstractmethod def get_by_id(self, *, id_: UUID) -> UserModel: pass @abstractmethod def save(self, *, data: UserModel) -> None: pass @abstractmethod def list_(self) -> list[UserModel]: pass</code>
次に、注入用の依存関係を初期化します。
<code class="language-python">from src.adapters.repositories.in_memory.user import MemoryUserRepository from src.constants.injection import MEMORY_REPOSITORY_CONFIG_TOKEN from .di import pydit from .get_db_config import get_db_config def setup_dependencies(): pydit.add_dependency(get_db_config, token=MEMORY_REPOSITORY_CONFIG_TOKEN) pydit.add_dependency(MemoryUserRepository, "UserRepository")</code>
最後に、ユーザーを作成するモジュールに依存関係を挿入します。
<code class="language-python">from typing import cast from src.adapters.repositories.interfaces.user import UserRepository from src.configs.di import pydit from src.domain.user.models.create_user import CreateUserModel from src.domain.user.models.user import UserModel from src.domain.user.services.create import CreateUserService from src.domain.user.services.list import ListUsersService class UserModule: @pydit.inject() def user_repository(self) -> UserRepository: return cast(UserRepository, None) def create(self, data: CreateUserModel) -> None: CreateUserService(self.user_repository).execute(data) def list_(self) -> list[UserModel]: return ListUsersService().execute()</code>
依存関係はプロパティとして挿入され、 self
または module.user_repository
を介してアクセスできます。
この例は単純ですが、PyDIT はさまざまなプロジェクト構成、コードの抽象化、および SOLID 原則のシナリオに適用できます。コードを試して貢献することを歓迎します。
コードリポジトリ: Github
LinkedIn: マルセロ アルメイダ (MrM4rc)
PyPI: python-pydit
以上がPython での入力の影響の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。