--Lorsque je pratiquais l'écriture de code avec DDD, j'ai essayé et erroné la méthode de vérification de type de ValueObject, donc un mémo à ce moment-là
__post_init__ ()
, le contrôle de type est exécuté ici.self .__ annotations__
--Convertissez une instance en dict avec dataclasses.asdict (self)
. Multipliez cela par une instance.--__ init__ () est généré automatiquement.
__init __ ()
et de faire self.hoge = arg_hoge
.
--Convient pour créer ValueObject.
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
Il vaut mieux écrire dans la classe de données!
C'est le sujet principal.
Je tape avec ʻuser_name: str et ʻuser_id: int
, et il semble que je vérifie le type, mais c'est en fait une annotation normale.
Même s'il est spécifié comme type str, il est entré comme type int.
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='Flamme de Serre')
print(f'{c_fail.user_id}:{c_fail.user_name}')
> python .\test de classe de données.py
1:Hinoya Koma
Flamme de Serre:2
Tout peut être mis comme ci-dessus.
__post_init__ ()
En définissant la fonction __post_init__ ()
dans la classe de données comme indiqué ci-dessous, vous pouvez écrire le traitement au moment de l'initialisation.
Tapons check ici en utilisant ʻis instance`
@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 .\test de classe de données.py
1:Hinoya Koma
Traceback (most recent call last):
File ".\test de classe de données.py", line 17, in <module>
c_fail = User(user_name=2, user_id='Flamme de Serre')
File "<string>", line 4, in __init__
File ".\test de classe de données.py", line 10, in __post_init__
raise Exception
Exception
Comme prévu, j'ai pu faire une exception!
Dans les exemples jusqu'à présent, il y en avait deux, ʻuser_name et ʻuser_id
, mais c'est difficile s'il y en a beaucoup.
Par conséquent, je veux limiter le nombre de vérifications de type écrites dans __post_init__
au nombre de variables.
C'est pourquoi j'ai écrit ce qui suit.
@dataclasses.dataclass(frozen=True)
class User:
user_name: str
user_id: int
def __post_init__(self):
# 1.Convertir l'instance utilisateur en type dict avec asdict
user_dict = dataclasses.asdict(self)
# 2. self.__annotations__Obtenez le type de valeur attendu à partir de
# self.__annotations__Contient le nom de l'argument et le type spécifié par celui-ci en tant que dict.
#A partir de maintenant, récupérez le type de la valeur attendue et vérifiez le type avec isinstance.
for user_arg_name, user_arg_expected_type in self.__annotations__.items():
# 3.est l'exécution de l'instance
#À partir du type Utilisateur converti en dict, spécifiez la variable cible avec la clé de l'annotation et exécutez-la.
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')
J'ai mis les détails dans les commentaires.
Obtenez tous les arguments (variables) que l'instance a avec ʻasdict, obtenez le type de valeur attendue avec
auto .__ annotations__, et multipliez par ʻis instance
.
En excluant les commentaires et `` imprimer '', vous pouvez écrire en 4 ou 5 lignes environ
> python .\test de classe de données.py
user_name is ok
user_id is ok
1:Hinoya Koma
user_name is not ok
Traceback (most recent call last):
File ".\test de classe de données.py", line 21, in <module>
c_fail = User(user_name=2, user_id='Flamme de Serre')
File "<string>", line 4, in __init__
File ".\test de classe de données.py", line 13, in __post_init__
raise Exception
Exception
Si vous spécifiez le type avec la saisie, etc., cette méthode ne fonctionnera pas.
Ce qui suit est celui dans lequel le type d'argument est spécifié par List [int]
sans commentaires.
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='Flamme de Serre', status_list=status_list)
print(f'{c_fail.user_id}:{c_fail.user_name}')
J'obtiens une erreur dans la liste comme indiqué ci-dessous.
> python .\.py
user_name is ok
user_id is ok
Traceback (most recent call last):
File ".\.py", line 27, in <module>
c = User(user_name='', user_id=1, status_list=status_list)
File "<string>", line 5, in __init__
File ".\.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
>>> from typing import List
>>> print(type(List[dir]))
<class 'typing._GenericAlias'>
test de classe de données Test de classe de données Hinoyakoma Vous pouvez voir pourquoi ce n'est pas bon en exécutant ce qui suit, mais List [int] est un type pour spécifier un type, donc ce n'est pas un type de liste réel. Il semble qu'il soit nécessaire de convertir au moment de la vérification de type.
La vérification de type en utilisant «post_init» semble correcte.
Cependant, si vous utilisez typing
lors de la spécification du type, il semble que vous ayez besoin de trouver un autre moyen de vérifier en le tournant avec l'instruction for.
Il peut être possible de vérifier de l'extérieur au lieu de le mettre dans le code avec mypy
etc.
(Si l'environnement est solide, comme la confirmation automatique au moment du push, ceci est également disponible)
--Python Documentation contents dataclasses --- Dataclasses
Recommended Posts