使用现有类的构造函数在Python中生成类。

huangapple go评论83阅读模式
英文:

Generating classes in python by using an exisiting one's constructor

问题

我想生成一些类,它们可以自动使用枚举中的值来设置现有的FieldDescriptor

我想生成以下类,而不编写它们:

  • GEN_STINGGEN_BIGINTGEN_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__,
    }

    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}")

这个问题的正确解决方案是什么?

英文:

I want to generate some classes, which automatically sets an existing one FieldDescriptor by using the values from enum.

I want to generate the following classes without writing them:

  • GEN_STING, GEN_BIGINT, GEN_FLOAT

For some reason I always have problem with the:

  • constructor
  • instantiation
  • number of arguments in __init__()

What is the proper solution for this?

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}")

What is the proper solution for this?

答案1

得分: 2

The easiest fix you can make is to change:

将最简单的修复方法更改为:

"init": lambda x, y: FieldDescriptor.init(x, y, field_type),

"init":lambda self, x, y: FieldDescriptor.init(self, x, y, field_type),

You were forgetting to provide your __init__ function with an self argument and passing that to FieldDescriptor.__init__.

您忘记为您的 __init__ 函数提供 self 参数并将其传递给 FieldDescriptor.__init__

If you want to use super, you could, you just cannot use the zero-argument form. You would need something like:

如果要使用 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

so create the class first so you can reference it and make the super call correctly.

因此,首先创建类,以便您可以引用它并正确进行 super 调用。

英文:

The easiest fix you can make is to change:

 "__init__": lambda x, y: FieldDescriptor.__init__(x, y, field_type),

To:

 "__init__": lambda self, x, y: FieldDescriptor.__init__(self, x, y, field_type),

You were forgetting to provide your __init__ function with an self argument and passing that to FieldDescriptor.__init__.

If you want to use super, you could, you just cannot use the zero-argument form. You would need something like:

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

so create the class first so you can reference it and make the super call correctly.

答案2

得分: 1

evalexec 可以帮助。

# 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'>
英文:

eval and exec can help.

# 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 = {
        &quot;__init__&quot;: __init__,
    }

    return type(class_name, (FieldDescriptor,), attrs)

generated_classes = {}
for value in FieldPairingTypes:
    class_name = &quot;GEN_&quot; + str(value).split(&quot;.&quot;)[-1]
    exec(f&#39;{class_name} = generate_class(class_name, value)&#39;)
    generated_classes[class_name] = eval(class_name)

# your code below

IDE will display this.

GEN_STRING: &lt;class &#39;str&#39;&gt;
GEN_BIGINT: &lt;class &#39;numpy.int64&#39;&gt;
GEN_FLOAT: &lt;class &#39;numpy.float64&#39;&gt;

huangapple
  • 本文由 发表于 2023年5月24日 22:37:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76324705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定