从字符串列表构建类名
我在 Tkinter
中创建了 Frame
和 Label
的子类,这样可以自动调用 .pack()
方法(这只是一个使用示例,我的问题并不严格与 Tkinter
相关)。这两个类的定义几乎是一样的,除了标签部分:
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
" 在类内部有不同的含义(比如类名、实际的类等等),所以我在尝试理解是否可以用类似于(这只是伪代码,试图解释我的观点)的方法来处理:
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:我认为这个问题和 另一个问题非常相似,但涉及的是 Objective-C
注意 2:我故意省略了 tkinter
标签,因为我给出的例子只是一个一般情况的特定实例
1 个回答
1
你可以使用 type()
函数 动态创建类:
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)
当你给 type()
函数传入三个参数时,它就会根据这些参数生成一个类。第一个参数是类的名字,第二个参数是一个包含基类的元组,第三个参数是一个表示类内容的映射。
这里需要用到 object
这个基类,以便它能和 Tkinter
模块中的旧式类一起工作。
另一种选择是把 class
语句放在一个函数里:
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
基类了。