编程语言
首页 > 编程语言> > python-无法更改__class__的PySide.QtGui对象

python-无法更改__class__的PySide.QtGui对象

作者:互联网

我已经使用了很多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''

标签:pyside,pyqt4,python
来源: https://codeday.me/bug/20191101/1982563.html