关于python:从字符串列表中构建类名

Building class names from a list of strings

本问题已经有最佳答案,请猛点这里访问。

我将Tkinter中的FrameLabel分为两个子类,以便自动地.pack()它们(这只是一个用法示例,我的问题与tkinter无关)。两个类的定义相同,但标签除外:

1
2
3
4
5
6
7
8
9
10
11
class Frame(tk.Frame):
    def __init__(self, parent, **kwargs):
        objparams, packparams = dispatch_parameters(self, **kwargs)
        tk.Frame.__init__(self, parent, objparams)
        self.pack(packparams)

class Label(tk.Label):
    def __init__(self, parent, **kwargs):
        objparams, packparams = dispatch_parameters(self, **kwargs)
        tk.Label.__init__(self, parent, objparams)
        self.pack(packparams)

为了避免对这两个类重复相同的代码,我想知道如何通过改变"标签"来重用它。我知道上面的"Frame表示类内的不同事物(类名、实际类等),所以我试着理解沿着(这是试图解释我的观点的伪代码)这一行看东西是否正确。

1
2
3
4
5
6
for classname in ["Frame","Label"]:
  class <<classname>>(tk.<<classname>>):
    def __init__(self, parent, **kwargs):
        objparams, packparams = dispatch_parameters(self, **kwargs)
        tk.<<classname>>.__init__(self, parent, objparams)
        self.pack(packparams)

对于这种代码重用的情况,是否有一种Python式的方法?或者我应该坚持一个接一个地定义类,即使代码非常相似?

注1:我认为这个问题与另一个问题非常相似,但对于目标C而言

注2:我故意省略了Tkinter标记,因为我给出的示例只是一般情况的一个特定实例。


可以使用type()函数动态创建类:

1
2
3
4
5
6
7
8
9
10
11
12
def class_factory(classname):
    base_class = getattr(tk, classname)

    def __init__(self, parent, **kwargs):
        objparams, packparams = dispatch_parameters(self, **kwargs)
        base_class.__init__(self, parent, objparams)
        self.pack(packparams)

    return type(classname, (base_class, object), {'__init__': __init__})

for classname in ["Frame","Label"]:
    globals()[classname] = class_factory(classname)

当给定3个参数时,type()函数从这些参数生成一个类。第一个参数是名称,第二个参数是基类的元组,第三个参数是表示类体的映射。

这里需要使用object库来处理来自Tkinter模块的旧样式类。

另一种选择是将class语句的作用范围限定为:

1
2
3
4
5
6
7
8
9
10
11
def class_factory(classname):
    base_class = getattr(tk, classname)

    class CustomClass(base_class):
        def __init__(self, parent, **kwargs):
            objparams, packparams = dispatch_parameters(self, **kwargs)
            base_class.__init__(self, parent, objparams)
            self.pack(packparams)

    CustomClass.__name__ = classname
    return CustomClass

这里我们不需要混合使用object基类。