PySide 使用Shiboken从其 C++ 类生成 Qt 的 CPython 绑定。所有的 Qt python 类,例如QPushButton
都是用 C++ 实现的,这就是为什么你不能覆盖__class__
.
>>> button = QPushButton()
>>> button.__class__ = MyButton
TypeError: __class__ assignment: only for heap types
根据 Shiboken 的文档,
只要方法是虚拟的(可覆盖),您就可以对已实例化的对象上的方法进行修补(或打孔):
import types
def override_text(self):
return 'overridden'
# Bind override_text() to button.
button.text = types.MethodType(override_text, button, QPushButton)
更进一步,您可以将其子类QPushButton
化为MyButton
,并将方法从动态注入MyButton
到QPushButton
实例中。创建MyButton
一个子类纯粹是可选的,但是
除了修改的实例之外,QPushButton
您还可以创建自己的实例。MyButton
QPushButton
让我们定义MyButton
为 的子类QPushButton
。
class MyButton(QPushButton):
def text(self):
# This will override QPushButton's text() method.
print("inside MyButton.text()")
return QPushButton.text(self)
- 注意:您必须使用旧式调用父类方法。
super()
以 a 失败,因为注入方法时TypeError
self 实际上是 aQPushButton
而不是 a 。MyButton
或者,如果您想采用更多的 mixin 方法,让我们定义MyButtonOverrides
:
class MyButtonOverrides(object):
def text(self):
# This will override QPushButton's text() method.
print("inside MyButtonOverrides.text()")
return self.__class__.text(self)
- 注意:您可以直接调用,
QPushButton.text()
因为self.__class__
您不会MyButtonOverrides
直接使用。
现在让我们定义extend_instance()
哪个会将您的覆盖方法从MyButton
(或MyButtonOverrides
)注入到QPushButton
实例中:
import inspect
def extend_instance(obj, cls):
for name, attr in vars(cls).items():
if inspect.isroutine(attr):
# Bind instance, class and static methods to *obj*.
setattr(obj, name, attr.__get__(obj, obj.__class__))
如果您希望您的类方法保持绑定到它们的原始类(例如,MyButton
),请使用以下内容:
def extend_instance(obj, cls):
for name, attr in vars(cls).items():
if inspect.isroutine(attr):
if isinstance(attr, classmethod):
# Bind class methods to *cls*.
setattr(obj, name, attr.__get__(cls, cls))
else:
# Bind instance and static methods to *obj*.
setattr(obj, name, attr.__get__(obj, obj.__class__))
通过我的测试,这适用于 Python 2.7 和 3.3,但应该适用于 2.6+ 和 3+。
最后要修改按钮,使用extend_instance()
.
>>> button = QPushButton()
>>> extend_instance(button, MyButton)
>>> button.text()
inside MyButton.text()
u''