首页 > 后端开发 > Python教程 > Python 中输入的影响

Python 中输入的影响

Susan Sarandon
发布: 2025-01-16 22:13:14
原创
579 人浏览过

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
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板