__post_init__ ()
angewendet wird, wird hier die Typprüfung ausgeführt.
--Type check with is instance--__ init__ () wird automatisch generiert.
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
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}')
> python .\Datenklassentest.py
1:Hinoya Koma
Talonflame:2
Alles kann wie oben eingegeben werden.
__post_init__ ()
durchDurch 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
> 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!
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
> 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
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
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.
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.)
--Python Documentation-Inhalt Datenklassen --- Datenklassen
Recommended Posts