英文:
Generating classes in python by using an exisiting one's constructor
问题
我想生成一些类,它们可以自动使用枚举中的值来设置现有的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__,
}
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
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'>
英文:
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 = {
"__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 will display this.
GEN_STRING: <class 'str'>
GEN_BIGINT: <class 'numpy.int64'>
GEN_FLOAT: <class 'numpy.float64'>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论