你能在 python 中循环制作 类 吗?

Can you make classes in a loop in python?

我有一种情况,我正在制作一堆 classes,其中一堆实际上基本相同,所以我想循环制作它们。它们与注册系统一起使用,因此在 USAGE 方面没有问题,但我不确定如何使用确定 class 名称的变量实际定义 class...

简单示例:

classList = ['foo', 'bar', 'baz']

for className in classList:
    class {{{className}}}_calc(BaseCalc): 
         def __init__ (self, dataFrame):
             self.column = dataFrame[className]
         def calc ():
             return self.column.sum()

显然,这是一个非常简化的案例。我无法将参数更改为 init,因为已经存在一大堆这些参数,它们是更大结构的一部分。

该示例的其余部分使用 pandas 语法,只是为了了解它是如何使用的...但它实际上是与 SQL 数据库一起使用的,而且很多更复杂……我只是不想为“你一开始为什么要这样做?”辩护。我有充分的理由,就这样吧。

classname 在 class 行的 {{{ }}} 中,表示它是一个变量,实际上在语法上并不正确。问题是“我如何表示我使用 {{{ }}} 的目的?”我觉得。

答案可能是 metaclasses,但我仍然不确定如何为我的 class 变量命名....

预计到达时间:尝试使用@python_user 答案:

classList = ['foooo', 'bar', 'baaz']

class Base ():
    def __init__ (self, buq):
        self.buq = buq

    def getBuq(self):
        return 'buq: ' + self.buq
    

for cls in classList:
    class TEMP(Base):
        className = cls
        def __init__ (self):
            self.qux = len(cls)
            Base.__init__(self, cls)

        def blee(self, inpt):
            return inpt+ self.qux
    TEMP.__name__ = f'{cls}'
    TEMP.__qualname__ = f'{cls}'
    globals()[cls] = TEMP
f = foo()

f.getBuq()

>>>> 'buq: baaz'

这只会给我带来麻烦 class。三个人都在胡闹……我是不是在做一些很蠢的事情?

但是,您可以使用 type 函数来创建这样的动态 classes。 names = ['name1', 'name2'] 假设你必须在 python 中创建 10 个 class 对象,并用它们做一些事情,比如: obj_1 = MyClass( ) other_object.

希望能帮到你。

好吧,有一种使用“exec()”函数执行此操作的混乱方法,该函数接受任何字符串并执行它;然后你可以将你的 类 构建为一个字符串和 运行 。这是构建您的 类 的示例,您可以通过查看最后打印的全局命名空间来看到它们是声明的。

classList = ['foo', 'bar', 'baz']

class BaseCalc(): 
     def __init__ (self, dataFrame):
         self.column = dataFrame[className]
     def calc ():
         return self.column.sum()

for className in classList:
    template = '''class %s_calc(BaseCalc): 
         def __init__ (self, dataFrame):
             self.column = dataFrame[className]
         def calc ():
             return self.column.sum()''' % className
    exec(template)

print(globals())

你可以这样做,使用 globals()

classList = ['foo', 'bar', 'baz']

for className in classList:
    class Temp:
        def __init__ (self, dataFrame):
            self.column = dataFrame[className]
        def calc ():
            return self.column.sum()
    Temp.__name__ = className
    globals()[className] = Temp

然后您可以执行 foo() 来创建 class foo 的对象。对于实际示例,您必须调用 __init__ 方法所需的参数。这只是为了证明它有效。

print(type(foo()).__name__) # foo
print(type(bar()).__name__) # bar
print(type(baz()).__name__) # baz

如果你想更改你的class名字,那么你可以

Temp.__name__ = f'{className}_calc'
globals()[f'{className}_calc'] = Temp

正如 wim 在评论中指出的,您还需要设置 __qualname__Temp.__qualname__ = f'{className}_calc'

编辑:

由于 class 的方法中的名称查找是在运行时(而非编译时)执行的,因此代码片段存在一个错误。 className 将始终引用 classList 中的最后一个元素(在本例中为 baz),此名称存在于循环范围之外,并将成为 className 的值在所有 classes 的方法中。 (例如:self.column = dataFrame[className])。 <--- 这总是 dataFrame['baz']

要解决此问题,必须声明一个名为 className 的 class 级别变量,并将 className(循环中的变量)分配给它。所以在编译时这个值将被绑定到 class。 class 的方法中对 className 的所有引用都需要更改为 self.className 才能使代码按预期工作。

class Temp:
    className = className # note this line
    def __init__ (self, dataFrame):
        self.column = dataFrame[self.className] # and this line with the original snippet