Python 中输入的影响
Python 3.5 版本引入了“类型提示”,使代码更易读,方便开发者理解彼此的代码。
为什么类型提示至关重要?
在 Java、C 等强类型语言中,依赖反转 (DI - Dependency Inversion) 是一项重要的技术,但在弱类型语言中难以实现。
依赖反转的核心思想是:类不应该依赖具体的实现,而应该依赖抽象。因为抽象(接口或抽象类)是相对稳定的契约。
不良示例:
class GasStation: def fill_tank(car, amount): car.fill(amount)
此例中,加油站只能为汽车加油。更糟糕的是,由于函数 fill_tank
没有定义类型,任何值都可能被传入,错误只能在运行时才能发现。
良好示例:
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)
此例中,先定义抽象类 Vehicle
(使用 typing.Protocol
)。GasStation
的 fill_tank
函数不再依赖具体的汽车类,而是依赖 Vehicle
接口,从而变得更通用,可以为任何实现了 fill
方法的车辆加油。
什么是 PyDIT?
我利用 Python 的类型提示系统,创建了一个简化依赖反转使用的库,名为 PyDIT (Python Dependency Injection with Types)。
假设需要一个用于存储用户数据的数据库接口,无论使用 PostgreSQL、MySQL、OracleDB、内存数据库还是 NoSQL 数据库,都需要实现数据库连接类,并提供读、写、删记录的功能。
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")
为了保证代码与数据库技术无关,定义一个所有数据库类都必须遵循的接口:
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
接下来,初始化依赖项以便注入:
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")
最后,将依赖项注入到创建用户的模块中:
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()
依赖项作为属性注入,可以通过 self
或 module.user_repository
访问。
这个例子很简单,但 PyDIT 可以应用于各种项目配置、代码抽象和 SOLID 原则的场景。欢迎尝试并贡献代码!
代码仓库:Github
LinkedIn:Marcelo Almeida (MrM4rc)
PyPI:python-pydit
以上是Python 中输入的影响的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Linux终端中查看Python版本时遇到权限问题的解决方法当你在Linux终端中尝试查看Python的版本时,输入python...

在使用Python的pandas库时,如何在两个结构不同的DataFrame之间进行整列复制是一个常见的问题。假设我们有两个Dat...

如何在10小时内教计算机小白编程基础?如果你只有10个小时来教计算机小白一些编程知识,你会选择教些什么�...

使用FiddlerEverywhere进行中间人读取时如何避免被检测到当你使用FiddlerEverywhere...

本文讨论了诸如Numpy,Pandas,Matplotlib,Scikit-Learn,Tensorflow,Tensorflow,Django,Blask和请求等流行的Python库,并详细介绍了它们在科学计算,数据分析,可视化,机器学习,网络开发和H中的用途

Uvicorn是如何持续监听HTTP请求的?Uvicorn是一个基于ASGI的轻量级Web服务器,其核心功能之一便是监听HTTP请求并进�...

在Python中,如何通过字符串动态创建对象并调用其方法?这是一个常见的编程需求,尤其在需要根据配置或运行...
