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

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

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

问题

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

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

  • GEN_STINGGEN_BIGINTGEN_FLOAT

出于某种原因,我总是在以下方面遇到问题:

  • 构造函数
  • 实例化
  • __init__()中的参数数量

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

  1. from enum import Enum
  2. from typing import Union, Type
  3. from dataclasses import dataclass
  4. import numpy as np
  5. class FieldPairingTypes(Enum):
  6. STRING = (str, "string", "keyword")
  7. BIGINT = (np.int64, "bigint", "long")
  8. FLOAT = (np.float64, "double", "double")
  9. @dataclass
  10. class FieldDescriptor:
  11. original_field_name: str
  12. datalake_field_name: str
  13. datalake_field_type: Type
  14. glue_field_type: str
  15. datamart_field_type: Union[str, Type]
  16. def __init__(self, ofn, dfn, field_type: FieldPairingTypes):
  17. self.original_field_name = ofn
  18. self.datalake_field_name = dfn
  19. self.datalake_field_type, self.glue_field_type, self.datamart_field_type = field_type.value
  20. def generate_class(class_name, field_type):
  21. def __init__(self, ofn, dfn):
  22. super().__init__(ofn, dfn, field_type)
  23. attrs = {
  24. "__init__": __init__,
  25. }
  26. return type(class_name, (FieldDescriptor,), attrs)
  27. generated_classes = {}
  28. for value in FieldPairingTypes:
  29. class_name = "GEN_" + str(value).split(".")[-1]
  30. generated_classes[class_name] = generate_class(class_name, value)
  31. for class_name, generated_class in generated_classes.items():
  32. instance = generated_class("Hello", "World")
  33. 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?

  1. from enum import Enum
  2. from typing import Union, Type
  3. from dataclasses import dataclass
  4. import numpy as np
  5. class FieldPairingTypes(Enum):
  6. STRING = (str, "string", "keyword")
  7. BIGINT = (np.int64, "bigint", "long")
  8. FLOAT = (np.float64, "double", "double")
  9. @dataclass
  10. class FieldDescriptor:
  11. original_field_name: str
  12. datalake_field_name: str
  13. datalake_field_type: Type
  14. glue_field_type: str
  15. datamart_field_type: Union[str, Type]
  16. def __init__(self, ofn, dfn, field_type: FieldPairingTypes):
  17. self.original_field_name = ofn
  18. self.datalake_field_name = dfn
  19. self.datalake_field_type, self.glue_field_type, self.datamart_field_type = field_type.value
  20. def generate_class(class_name, field_type):
  21. def __init__(self, ofn, dfn):
  22. super().__init__(ofn, dfn, field_type)
  23. attrs = {
  24. # "__init__": __init__,
  25. #"__init__": FieldDescriptor.__init__,
  26. "__init__": lambda x, y: FieldDescriptor.__init__(x, y, field_type),
  27. }
  28. return type(class_name, (FieldDescriptor,), attrs)
  29. generated_classes = {}
  30. for value in FieldPairingTypes:
  31. class_name = "GEN_" + str(value).split(".")[-1]
  32. generated_classes[class_name] = generate_class(class_name, value)
  33. for class_name, generated_class in generated_classes.items():
  34. instance = generated_class("Hello", "World")
  35. 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):

  1. klass = type(class_name, (FieldDescriptor,), {})
  2. def __init__(self, ofn, dfn):
  3. super(klass, self).__init__(ofn, dfn, field_type)
  4. klass.__init__ = __init__
  5. 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:

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

To:

  1. "__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:

  1. def generate_class(class_name, field_type):
  2. klass = type(class_name, (FieldDescriptor,), {})
  3. def __init__(self, ofn, dfn):
  4. super(klass, self).__init__(ofn, dfn, field_type)
  5. klass.__init__ = __init__
  6. return klass

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

答案2

得分: 1

evalexec 可以帮助。

  1. # your code above
  2. def generate_class(class_name, field_type):
  3. def __init__(self, ofn, dfn):
  4. super(eval(class_name), self).__init__(ofn, dfn, field_type)
  5. attrs = {
  6. "__init__": __init__,
  7. }
  8. return type(class_name, (FieldDescriptor,), attrs)
  9. generated_classes = {}
  10. for value in FieldPairingTypes:
  11. class_name = "GEN_" + str(value).split(".")[-1]
  12. exec(f'{class_name} = generate_class(class_name, value)')
  13. generated_classes[class_name] = eval(class_name)
  14. # your code below

IDE 会显示以下内容:

  1. GEN_STRING: <class 'str'>
  2. GEN_BIGINT: <class 'numpy.int64'>
  3. GEN_FLOAT: <class 'numpy.float64'>
英文:

eval and exec can help.

  1. # your code above
  2. def generate_class(class_name, field_type):
  3. def __init__(self, ofn, dfn):
  4. super(eval(class_name), self).__init__(ofn, dfn, field_type)
  5. attrs = {
  6. &quot;__init__&quot;: __init__,
  7. }
  8. return type(class_name, (FieldDescriptor,), attrs)
  9. generated_classes = {}
  10. for value in FieldPairingTypes:
  11. class_name = &quot;GEN_&quot; + str(value).split(&quot;.&quot;)[-1]
  12. exec(f&#39;{class_name} = generate_class(class_name, value)&#39;)
  13. generated_classes[class_name] = eval(class_name)
  14. # your code below

IDE will display this.

  1. GEN_STRING: &lt;class &#39;str&#39;&gt;
  2. GEN_BIGINT: &lt;class &#39;numpy.int64&#39;&gt;
  3. 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:

确定