[Python] Einfache Überprüfung des Argumenttyps mit Datenklasse

Einführung

Fazit

Was ist eine Datenklasse?

--__ init__ () wird automatisch generiert.

Normales Schreiben


class Users:
    def __init__(self, user_name: str, user_id: int):
        self.user_name = user_name
        self.user_id = user_id


class User:
    user_name: str
    user_id: int

Es ist besser, in Datenklasse zu schreiben! Können Sie check mit Datenklasse eingeben? Dies ist das Hauptthema. Es wird mit user_name: str oder user_id: int eingegeben und es sieht so aus, als ob es typgeprüft ist, aber es ist eigentlich eine normale Anmerkung. Obwohl es als str-Typ angegeben ist, wird es als int-Typ eingegeben. Code


import dataclasses

@dataclasses.dataclass(frozen=True)
class User:
    user_name: str
    user_id: int

c = User(user_name='Hinoya Koma', user_id=1)
print(f'{c.user_id}:{c.user_name}')

c_fail = User(user_name=2, user_id='Talonflame')
print(f'{c_fail.user_id}:{c_fail.user_name}')

Ausführungsergebnis


> python .\Datenklassentest.py
1:Hinoya Koma
Talonflame:2

Alles kann wie oben eingegeben werden.

Führen Sie bei der Initialisierung eine Typprüfung mit __post_init__ () durch

Durch Definieren der Funktion __post_init__ () in der Datenklasse wie unten gezeigt können Sie die Verarbeitung zum Zeitpunkt der Initialisierung schreiben. Geben Sie hier check mit is instance ein


@dataclasses.dataclass(frozen=True)
class User:
    user_name: str
    user_id: int

    def __post_init__(self):
        if not isinstance(self.user_name, str):
            raise Exception
        if not isinstance(self.user_id, int):
            raise Exception

Ausführungsergebnis


> python .\Datenklassentest.py
1:Hinoya Koma
Traceback (most recent call last):
  File ".\Datenklassentest.py", line 17, in <module>
    c_fail = User(user_name=2, user_id='Talonflame')
  File "<string>", line 4, in __init__
  File ".\Datenklassentest.py", line 10, in __post_init__
    raise Exception
Exception

Wie erwartet konnte ich eine Ausnahme machen!

Die Typprüfung ist schwierig, wenn viele Variablen vorhanden sind

In den bisherigen Beispielen gab es zwei, "Benutzername" und "Benutzer-ID", aber es ist schwierig, wenn es viele gibt. Daher möchte ich die Anzahl der in __post_init__ geschriebenen Typprüfungen auf die Anzahl der Variablen beschränken.

Deshalb habe ich folgendes geschrieben.


@dataclasses.dataclass(frozen=True)
class User:
    user_name: str
    user_id: int

    def __post_init__(self):
        # 1.Konvertieren Sie die Benutzerinstanz in den Diktattyp mit asdict
        user_dict = dataclasses.asdict(self)
        # 2. self.__annotations__Holen Sie sich den erwarteten Werttyp von
        #    self.__annotations__Enthält den Namen des Arguments und den angegebenen Typ als Diktat.
        #Holen Sie sich von nun an den Typ des erwarteten Werts und überprüfen Sie den Typ mit isinstance.
        for user_arg_name, user_arg_expected_type in self.__annotations__.items():
            # 3.ist die Instanzausführung
            #Geben Sie vom Benutzer, der in den Diktattyp konvertiert wurde, die Zielvariable mit dem Schlüssel der Anmerkung an und führen Sie sie aus.
            if not isinstance(user_dict[user_arg_name], user_arg_expected_type):
                print(f'{user_arg_name} is not ok')
                raise Exception
            else:
                print(f'{user_arg_name} is ok')

Ich habe die Details in die Kommentare eingetragen. Holen Sie sich alle Argumente (Variablen), die die Instanz mit "asdict" hat, rufen Sie den erwarteten Werttyp mit "self .__ annotations__" ab und multiplizieren Sie mit "is instance". Ohne Kommentar und "Drucken" können Sie in etwa 4 oder 5 Zeilen schreiben

Ausführungsergebnis

> python .\Datenklassentest.py
user_name is ok
user_id is ok
1:Hinoya Koma
user_name is not ok
Traceback (most recent call last):
  File ".\Datenklassentest.py", line 21, in <module>
    c_fail = User(user_name=2, user_id='Talonflame')
  File "<string>", line 4, in __init__
  File ".\Datenklassentest.py", line 13, in __post_init__
    raise Exception
Exception

Schwächen dieses Codes

Wenn Sie den Typ mit Eingabe usw. angeben, funktioniert diese Methode nicht. Das Folgende ist derjenige, in dem der Argumenttyp durch "List [int]" ohne Kommentare angegeben wird.


import dataclasses
from typing import List 

@dataclasses.dataclass(frozen=True)
class User:
    user_name: str
    user_id: int
    status_list: List[int]

    def __post_init__(self):
        user_dict = dataclasses.asdict(self)
        for user_arg_name, user_arg_expected_type in self.__annotations__.items():
            if not isinstance(user_dict[user_arg_name], user_arg_expected_type):
                print(f'{user_arg_name} is not ok')
                raise Exception
            else:
                print(f'{user_arg_name} is ok')

status_list=[50,51]

c = User(user_name='Hinoya Koma', user_id=1, status_list=status_list)
print(f'{c.user_id}:{c.user_name}')

c_fail = User(user_name=2, user_id='Talonflame', status_list=status_list)
print(f'{c_fail.user_id}:{c_fail.user_name}')

Ich erhalte einen Fehler in der Liste, wie unten gezeigt.

> python .\Datenklassentest.py
user_name is ok
user_id is ok
Traceback (most recent call last):
  File ".\Datenklassentest.py", line 27, in <module>
    c = User(user_name='Hinoya Koma', user_id=1, status_list=status_list)
  File "<string>", line 5, in __init__
  File ".\Datenklassentest.py", line 19, in __post_init__
    if not isinstance(user_dict[user_arg_name], user_arg_expected_type):
  File "C:\Users\proje\AppData\Local\Programs\Python\Python37\lib\typing.py", line 708, in __instancecheck__
    return self.__subclasscheck__(type(obj))
  File "C:\Users\proje\AppData\Local\Programs\Python\Python37\lib\typing.py", line 716, in __subclasscheck__
    raise TypeError("Subscripted generics cannot be used with"
TypeError: Subscripted generics cannot be used with class and instance checks

Warum nicht

Wie Sie im Folgenden sehen können, ist List [int] ein Typ zum Angeben des Typs, also nicht der tatsächliche Listentyp.

>>> from typing import List 
>>> print(type(List[dir]))  
<class 'typing._GenericAlias'>

Es scheint notwendig zu sein, zum Zeitpunkt der Typprüfung zu konvertieren.

abschließend

Die Typprüfung mit __post_init__ scheint in Ordnung zu sein. Wenn Sie jedoch bei der Angabe des Typs "Typing" verwenden, müssen Sie anscheinend eine andere Methode zur Überprüfung entwickeln, indem Sie sie mit der for-Anweisung drehen. Es kann möglich sein, von außen zu überprüfen, anstatt es mit "mypy" usw. in den Code einzufügen. (Wenn die Umgebung solide ist, z. B. eine automatische Bestätigung zum Zeitpunkt des Pushs, ist dies ebenfalls verfügbar.)

Referenz

--Python Documentation-Inhalt Datenklassen --- Datenklassen

Recommended Posts

[Python] Einfache Überprüfung des Argumenttyps mit Datenklasse
Domaincheck mit Python
Python # Überprüfen Sie die Typidentität
Überprüfen Sie die Version mit Python
[Analyse des gemeinsamen Auftretens] Einfache Analyse des gemeinsamen Auftretens mit Python! [Python]
Überprüfen Sie die Python-Abdeckung mit pytest-cov
Python --Überprüfen Sie den Wertetyp
Einfache Ordnersynchronisation mit Python
Einfache Python-Kompilierung mit NUITKA-Utilities
Einfacher HTTP-Server mit Python
[Python] Einfache Parallelverarbeitung mit Joblib
Definition des Funktionsargumenttyps in Python
Einfache Python + OpenCV-Programmierung mit Canopy
Einfache Mailübertragung mit Eile Python3
Bayesianische Optimierung, die mit Python sehr einfach ist
Beherrsche den Typ mit Python [Python 3.9 kompatibel]
Visualisieren Sie Ihre Daten ganz einfach mit Python Seaborn.
Einfache parallele Ausführung mit Python-Unterprozess
Einfache Schlüsselwortextraktion mit TermExtract für Python
[Python] Super einfacher Test mit Assert-Anweisung
Überprüfen Sie die Existenz der Datei mit Python
Einfache Einführung der Spracherkennung mit Python
Überprüfen Sie die Aktienkurse mit Slackbot mit Python
Empfangen Sie den Datumstyp (Datum / Uhrzeit) mit ArgumentParser [Python]
[Easy Python] Lesen von Excel-Dateien mit openpyxl
Einfache Web-App mit Python + Flask + Heroku
Verarbeiten Sie Bilder in Python ganz einfach mit Pillow
[Easy Python] Lesen von Excel-Dateien mit Pandas
Einfaches Web-Scraping mit Python und Ruby
[Python] Probieren Sie mit Keras-RL ganz einfach erweitertes Lernen (DQN) aus
[Python] Einfache Einführung in das maschinelle Lernen mit Python (SVM)
FizzBuzz in Python3
CSV-Ausgabe der Google-Suche mit [Python]! 【Einfach】
Scraping mit Python
Python ist einfach
Numerischer Python-Typ
Statistik mit Python
Lesen Sie Daten mit python / netCDF> nc.variables [] / Überprüfen Sie die Datengröße
Überprüfen Sie Python-Skripte automatisch mit GitHub + Travis-CI + Pycodestyle
Python-Grammatikprüfung
Scraping mit Python
Python mit Go
Python> Laufzeitargument> Überprüfen Sie, ob -d angehängt ist
Twilio mit Python
In Python integrieren
Überprüfen Sie das Datum der Flaggenpflicht mit Python
Spielen Sie mit 2016-Python
AES256 mit Python
Getestet mit Python
Python beginnt mit ()
mit Syntax (Python)
Bingo mit Python
Zundokokiyoshi mit Python
Python2-Zeichenfolgentyp
Python # String-Typ
[Python] Bestimmen Sie den Typ der Iris mit SVM
Einfache LASSO-Regressionsanalyse mit Python (keine Theorie)
Excel mit Python