如何在运行时轻松选择PyQt或PySide?

5
我想在一个源文件QT.py中实现类似这样的功能:
import sys
import PyQt4

sys.modules["Qt"] = PyQt4

然后在其他源文件中导入此文件,并像这样使用它:

import QT
from Qt.QtCore import *

所以我可以在QT.py中从PyQt4更改为PySide,而不必触及所有源文件(可能使用丑陋的sed脚本)。这些模块大多是API兼容的,我想测试它们两个。有没有一种简单的方法来做到这一点?(因为我尝试过的方法都没有起作用)
也许我需要imp模块,但它似乎太低级了。
有什么想法吗?
3个回答

4
使用导入钩子(import hook):
def set_qt_bindings(package):
    if package not in ('PyQt4', 'PySide'):
        raise ValueError('Unknown Qt Bindings: %s' % package)
    import __builtin__
    __import__ = __builtin__.__import__
    def hook(name, globals=None, locals=None, fromlist=None, level=-1):
        root, sep, other = name.partition('.')
        if root == 'Qt':
            name = package + sep + other
        return __import__(name, globals, locals, fromlist, level)
    __builtin__.__import__ = hook

if __name__ == '__main__':

    import sys

    if len(sys.argv) > 1:

        set_qt_bindings(sys.argv[-1])

        import Qt
        print Qt

        from Qt import QtCore
        print QtCore

        from Qt.QtGui import QWidget
        print QWidget

输出:

$ python2 test.py PySide
<module 'PySide' from '/usr/lib/python2.7/site-packages/PySide/__init__.py'>
<module 'PySide.QtCore' from '/usr/lib/python2.7/site-packages/PySide/QtCore.so'>
<type 'PySide.QtGui.QWidget'>
$ python2 test.py PyQt4
<module 'PyQt4' from '/usr/lib/python2.7/site-packages/PyQt4/__init__.pyc'>
<module 'PyQt4.QtCore' from '/usr/lib/python2.7/site-packages/PyQt4/QtCore.so'>
<class 'PyQt4.QtGui.QWidget'>

2

更新:找到更符合您要求的方法:

您可以将伪模块结构化为:

Qt/
Qt/__init__.py
Qt/QtCore/__init__.py
Qt/QtGui/__init__.py

这里的 Qt/__init__.py 是什么:

import QtCore, QtGui

Qt/QtCore/__init__.py 是:

from PyQt4.QtCore import *

Qt/QtGui/__init__.py is:

from PyQt4.QtGui import *

然后,在您的代码中,您可以按如下方式引用它:
import sys
from Qt import QtGui
app = QtGui.QApplication(sys.argv)

from Qt.QtGui import *

window = QWidget()
window.show()

app.exec_()

强烈不建议在您的代码中使用from Qt.QtGui import *,因为导入所有内容被认为是Python中的坏习惯,因为这样会丢失所有命名空间。

更新:我喜欢Ryan的建议使用条件导入,并建议将其与上面的代码合并。例如:

Qt/QtGui/__init__.py

import sys
if '--PyQt4' in sys.argv:
    from PyQt4.QtGui import *
else:
    from PySide.QtGui import *

我不确定是否要将空伪模块添加到项目中,特别是因为PySide/PyQt包含更多的子模块。 - John T. Brown
@guttalax 你说这是用来测试的,对吧?我不想在生产环境中做这样的hacky操作。如果你正在生产环境中使用它,请勿使用import *。没有那个,你可以做一些简单的事情,比如Qt/__init__.py,其中__init__.pyfrom PyQt4 import *。然后,你可以将事物引用为Qt.QtGui.QWidget() - Nathan
嗯,是的,这是为了测试。你看,这是我的一个业余项目,我不介意使用一些hackish的解决方案。理想情况下,我希望能够提供一种简单的方法让其他人在pyside和pyqt之间切换,甚至让程序使用可用的任何一个。 - John T. Brown

0

您可以有条件地导入库。这里是一个有点hacky的例子,您可以检查命令行参数是否为“PyQt4”:

import sys

if sys.argv[-1] == 'PyQt4':
    import PyQt4
    sys.modules["Qt"] = PyQt4
else:
    import Qt
    from Qt.QtCore import *

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接