Maison > développement back-end > Tutoriel Python > L'impact de la saisie en Python

L'impact de la saisie en Python

Susan Sarandon
Libérer: 2025-01-16 22:13:14
original
578 Les gens l'ont consulté

O impacto da tipagem no python

Python version 3.5 introduit des « indices de type » pour rendre le code plus lisible et permettre aux développeurs de mieux comprendre le code de chacun.

Pourquoi les indices de type sont-ils importants ?

Dans les langages fortement typés comme Java et C, l'inversion de dépendances (DI - Dependency Inversion) est une technologie importante, mais elle est difficile à implémenter dans les langages faiblement typés.

L'idée centrale de l'inversion des dépendances est la suivante : les classes ne doivent pas s'appuyer sur des implémentations spécifiques, mais sur des abstractions. Car les abstractions (interfaces ou classes abstraites) sont des contrats relativement stables.

Mauvais exemple :

<code class="language-python">class GasStation:
    def fill_tank(car, amount):
        car.fill(amount)</code>
Copier après la connexion

Dans cet exemple, la station-service ne peut ravitailler que les voitures. Pour aggraver les choses, puisque la fonction fill_tank n'a pas de type défini, n'importe quelle valeur peut être transmise et l'erreur ne sera découverte qu'au moment de l'exécution.

Bon exemple :

<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>
Copier après la connexion

Dans cet exemple, définissez d'abord la classe abstraite Vehicle (en utilisant typing.Protocol). La fonction GasStation de fill_tank ne s'appuie plus sur une classe de voiture spécifique, mais sur l'interface Vehicle, devenant ainsi plus générale et pouvant faire le plein de tout véhicule mettant en œuvre la méthode fill.

Qu'est-ce que PyDIT ?

J'ai profité du système d'indication de types de Python et créé une bibliothèque qui simplifie l'utilisation de l'inversion de dépendances, appelée PyDIT (Python Dependency Injection with Types).

Supposons que vous ayez besoin d'une interface de base de données pour stocker les données utilisateur. Que vous utilisiez PostgreSQL, MySQL, OracleDB, une base de données en mémoire ou une base de données NoSQL, vous devez implémenter une classe de connexion à la base de données et fournir les fonctions de lecture, d'écriture et de suppression d'enregistrements. .

<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>
Copier après la connexion

Afin de garantir que le code n'a rien à voir avec la technologie des bases de données, définissez une interface que toutes les classes de bases de données doivent suivre :

<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>
Copier après la connexion

Ensuite, initialisez les dépendances pour l'injection :

<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>
Copier après la connexion

Enfin, injectez les dépendances dans le module qui crée l'utilisateur :

<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>
Copier après la connexion

Les dépendances sont injectées en tant que propriétés et sont accessibles via self ou module.user_repository .

Cet exemple est simple, mais PyDIT peut être appliqué à une variété de configurations de projet, d'abstractions de code et de scénarios de principe SOLID. Bienvenue pour essayer de contribuer au code !

Référentiel de code : Github
LinkedIn : Marcelo Almeida (MrM4rc)
PyPI : python-pydit

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal