Я хочу сгенерировать несколько классов, которые автоматически устанавливают существующий FieldDescriptor, используя значения из перечисления.
Я хочу создать следующие классы, не записывая их:
GEN_STING, GEN_BIGINT, GEN_FLOATПо какой-то причине у меня всегда есть проблема с:
__init__()Какое правильное решение для этого?
from enum import Enum
from typing import Union, Type
from dataclasses import dataclass
import numpy as np
class FieldPairingTypes(Enum):
STRING = (str, "string", "keyword")
BIGINT = (np.int64, "bigint", "long")
FLOAT = (np.float64, "double", "double")
@dataclass
class FieldDescriptor:
original_field_name: str
datalake_field_name: str
datalake_field_type: Type
glue_field_type: str
datamart_field_type: Union[str, Type]
def __init__(self, ofn, dfn, field_type: FieldPairingTypes):
self.original_field_name = ofn
self.datalake_field_name = dfn
self.datalake_field_type, self.glue_field_type, self.datamart_field_type = field_type.value
def generate_class(class_name, field_type):
def __init__(self, ofn, dfn):
super().__init__(ofn, dfn, field_type)
attrs = {
# "__init__": __init__,
#"__init__": FieldDescriptor.__init__,
"__init__": lambda x, y: FieldDescriptor.__init__(x, y, field_type),
}
return type(class_name, (FieldDescriptor,), attrs)
generated_classes = {}
for value in FieldPairingTypes:
class_name = "GEN_" + str(value).split(".")[-1]
generated_classes[class_name] = generate_class(class_name, value)
for class_name, generated_class in generated_classes.items():
instance = generated_class("Hello", "World")
print(f"{class_name}: {instance.datalake_field_type}")
Какое правильное решение для этого?






eval и exec могут помочь.
# your code above
def generate_class(class_name, field_type):
def __init__(self, ofn, dfn):
super(eval(class_name), self).__init__(ofn, dfn, field_type)
attrs = {
"__init__": __init__,
}
return type(class_name, (FieldDescriptor,), attrs)
generated_classes = {}
for value in FieldPairingTypes:
class_name = "GEN_" + str(value).split(".")[-1]
exec(f'{class_name} = generate_class(class_name, value)')
generated_classes[class_name] = eval(class_name)
# your code below
IDE отобразит это.
GEN_STRING: <class 'str'>
GEN_BIGINT: <class 'numpy.int64'>
GEN_FLOAT: <class 'numpy.float64'>
Самое простое исправление, которое вы можете сделать, это изменить:
"__init__": lambda x, y: FieldDescriptor.__init__(x, y, field_type),
К:
"__init__": lambda self, x, y: FieldDescriptor.__init__(self, x, y, field_type),
Вы забыли предоставить своей функции __init__ аргумент self и передать его FieldDescriptor.__init__.
Если вы хотите использовать super, вы можете, вы просто не можете использовать форму без аргументов. Вам понадобится что-то вроде:
def generate_class(class_name, field_type):
klass = type(class_name, (FieldDescriptor,), {})
def __init__(self, ofn, dfn):
super(klass, self).__init__(ofn, dfn, field_type)
klass.__init__ = __init__
return klass
поэтому сначала создайте класс, чтобы вы могли сослаться на него и правильно выполнить вызов super.