Генерация классов в python с использованием существующего конструктора

Я хочу сгенерировать несколько классов, которые автоматически устанавливают существующий 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}")

Какое правильное решение для этого?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
67
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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.

Другие вопросы по теме