If I create and specify a type directly as follows,
INT64 = int
BIGINT = int
VARCHAR256 = str
VARCHAR512 = str
@dataclass
class TempClass(object):
v1: INT64
v2: BIGINT
v3: VARCHAR256
v4: VARCHAR512
When checking the type of a dataclass variable, is there a way to check whether it is a directly specified type?
As a simple example, if you check the type as shown below, it would be nice to be able to output the specified INT64, BIGINT, VARCHAR256, or VARCHAR512 or check the type!
for _i in TempClass.__dataclass_fields__:
print(type(_i))
You can iterate over the fields()
of a dataclass in order to retrieve each field's name
and type
, as shown below.
However, note that doing so will only print the resolved type of each field, i.e. the type to the right of the equals =
sign below.
For instance, it will resolve the type of the first field -- v1
-- to int
, which is likely not what you intend or want.
from dataclasses import dataclass, fields
INT64 = int
BIGINT = int
VARCHAR256 = str
VARCHAR512 = str
@dataclass
class TempClass(object):
v1: INT64
v2: BIGINT
v3: VARCHAR256
v4: VARCHAR512
for field in fields(TempClass):
print(field.name, '-', field.type)
Prints:
v1 - <class 'int'>
v2 - <class 'int'>
v3 - <class 'str'>
v4 - <class 'str'>
To work around this, you can add the following to the top of your module:
from __future__ import annotations
This will convert all annotations in the module to a str
value, so that the annotations are lazy-evaluated.
This is useful in our case, so we know the actual name of the annotation passed in, rather than the resolved or evaluated type (int
for example).
Example:
from __future__ import annotations
from dataclasses import dataclass, fields
from sys import modules
INT64 = int
BIGINT = int
VARCHAR256 = str
VARCHAR512 = str
@dataclass
class TempClass(object):
v1: INT64
v2: BIGINT
v3: VARCHAR256
v4: VARCHAR512
# retrieve globals of the class's module
cls_globals = modules[TempClass.__module__].__dict__
# iterate over each dataclass field, retrieve its name and type
for field in fields(TempClass):
f_name = field.name
# field's annotation -- will be a "lazy-evaluated" string value
f_ann = field.type
# field's resolved type (for example `str` or `int`)
f_type = cls_globals[f_ann]
# custom name for the field's type
f_type_name = 'STRING' if f_type is str else 'NUMBER' if issubclass(f_type, (int, float)) else 'UNKNOWN'
print(f_name, '-->')
print(f' annotation (str): {f_ann!r}')
print(f' type: {f_type.__qualname__}')
print(f' type_name: {f_type_name}')
Output:
v1 -->
annotation (str): 'INT64'
type: int
type_name: NUMBER
v2 -->
annotation (str): 'BIGINT'
type: int
type_name: NUMBER
v3 -->
annotation (str): 'VARCHAR256'
type: str
type_name: STRING
v4 -->
annotation (str): 'VARCHAR512'
type: str
type_name: STRING