本节不是关于来自多个Qt类的子类。
协作多继承是一种用于实现继承多个超类的类的技术 - 通常是主超类和一个或多个添加其他行为的mixin类。它可以在以后添加新的mixin以便进一步扩展行为,而无需更改类的实现或创建类实例的任何现有代码。
该技术要求所有超类的__init__
方法遵循相同的模式,处理无法识别的关键字参数,并用于super()
调用自己的超类__init__
方法。
PyQt5的类遵循这种模式。
看Raymond Hettinger的Python超级()被认为超级!关于这个主题的一些更多背景的博客文章。
举个例子,假设我们有一个代表一个人的类,一个人有一个名字。以下可能是初始实现:
class Person(QObject):
def __init__(self, name, parent=None)
QObject.__init__(self, parent)
self.name = name
通常可以通过以下方式之一创建实例:
person = Person("Joe")
person = Person("Joe", some_parent)
这种方法有一些局限性:
- 仅公开QObject API 的子集。例如,您不能通过传递适当的关键字参数来设置Qt属性的值或连接信号
Person.__init__
。 - 将另一个类添加到
Person
超类列表中意味着__init__
需要更改其 实现。如果新的mixin采用非可选参数,则每次创建Person
实例的调用都需要更改。
考虑这个替代实现:
class Person(QObject):
def __init__(self, name, **kwds):
super().__init__(**kwds)
self.name = name
不同之处在于我们只处理Person
类本身使用的参数,并通过调用将所有其他参数归入超类super()
。
通过此实现,通常可以通过以下方式之一创建实例:
person = Person("Joe")
person = Person("Joe", parent=some_parent)
这里的区别在于我们使用关键字参数来指定Person
类本身未处理的任何参数。请注意,我们可以为所有参数使用关键字参数 - 无论您是否这样做都取决于个人选择。
第一次实施的限制不再适用。例如,如果没有任何进一步的更改,我们也可以这样做:
person = Person("Joe", destroyed=some_callable)
假设我们现在想Person
通过添加一个处理一个人年龄的mixin 来扩展类的行为。mixin的实现如下:
class Age(object):
def __init__(self, age=0, **kwds):
super().__init__(**kwds)
self.age = age
这遵循与我们的Person
实现类似的模式,但请注意我们为age
参数提供了默认值。
以下是我们的新Person
实现:
class Person(QObject, Age):
def __init__(self, name, **kwds):
super().__init__(**kwds)
self.name = name
我们必须做的唯一改变就是添加Age
到Person
超类的列表中。更重要的是,我们不需要更改任何调用来创建 Person
实例。
如果我们确实想要创建一个Person
非默认年龄的实例,那么我们只需将其作为关键字参数传递,如下所示:
person = Person("Joe", age=38)
这种技术增加了关键字参数的使用 - 虽然这意味着更多的输入,但它显着增加了应用程序代码的可读性。