首頁 > 後端開發 > Python教學 > Python 中輸入的影響

Python 中輸入的影響

Susan Sarandon
發布: 2025-01-16 22:13:14
原創
578 人瀏覽過

O impacto da tipagem no 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)。 GasStationfill_tank 函數不再依賴具體的汽車類,而是依賴 Vehicle 接口,從而變得更通用,可以為任何實現了 fill 方法的車輛加油。

什麼是 PyDIT?

我利用 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>
登入後複製

依賴項作為屬性注入,可以透過 selfmodule.user_repository 存取。

這個範例很簡單,但 PyDIT 可以應用於各種專案配置、程式碼抽象化和 SOLID 原則的場景。歡迎嘗試並貢獻程式碼!

代碼倉庫:Github
LinkedIn:Marcelo Almeida (MrM4rc)
PyPI:python-pydit

以上是Python 中輸入的影響的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板