我已经使用了很多PyQt4-有时我喜欢重载一些对象以允许添加一些功能.这在PyQt4中可以正常工作,例如:
from PyQt4 import QtGui
button = QtGui.QPushButton()
class MyPushButton(QtGui.QPushButton): pass
button.__class__ = MyPushButton
但是,我正在尝试调整我的一些代码,使其使用PySide而不是PyQt4.我的理解是它们应该具有相同的功能. PySide不允许我做同样的事情.
from PySide import QtGui
button = QtGui.QPushButton()
class MyPushButton(QtGui.QPushButton): pass
button.__class__ = MyPushButton
出现以下错误:
TypeError: __class__ assignment: only for heap types
还有另一种方法可以更改对象的类以避免此错误?我不太确定是什么原因造成的.
注意:创建对象后,我需要更改对象的类,因为在由pyuic编译的库中创建了对象.另外,我的PySide安装中没有uic模块.
解决方法:
PySide使用Shiboken从中生成Qt的CPython绑定
它的C类.所有Qt python类(例如QPushButton)都是
用C实现的,这就是为什么您不能覆盖__class__的原因.
>>> button = QPushButton()
>>> button.__class__ = MyButton
TypeError: __class__ assignment: only for heap types
根据Shiboken的文档,您可以monkey patch (or duck punch)
只要方法是已经存在的对象上的方法
虚拟(可覆盖):
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()因TypeError失败而失败,因为self实际上是一个QPushButton
而不是当方法被注入时的MyButton.
或者,如果您想采用更多的混合方法,那么请定义MyButtonOverrides:
class MyButtonOverrides(object):
def text(self):
# This will override QPushButton's text() method.
print("inside MyButtonOverrides.text()")
return self.__class__.text(self)
>注意:您可以直接通过self .__ class__调用QPushButton.text().
因为您不会直接使用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''