为了使我的代码与PyQt5/6和PySide2/6兼容,我写道:

if not hasattr(QtCore.QDateTime, 'toPython'):  # fix for PyQt5/6
    QtCore.QDateTime.toPython = QtCore.QDateTime.toPyDateTime

使用PyQt5或PyQt6运行,这会导致

TypeError: toPyDateTime(self): first argument of unbound method must have type 'QDateTime'

调用函数时:

QtCore.QDateTime.currentDateTime().toPython()

但如果我把电话换成

QtCore.QDateTime.toPython(QtCore.QDateTime.currentDateTime())

没有错误.

但是,当我将第一段代码更改为

if not hasattr(QtCore.QDateTime, 'toPython'):  # fix for PyQt5/6
    QtCore.QDateTime.toPython = lambda self: QtCore.QDateTime.toPyDateTime(self)

不管我怎么叫toPython函数,一切都很好.为什么我需要lambda表达式呢?

Added.为了解释我预期的行为,这里有一段简单的代码:

class A:
    def __init__(self) -> None:
        print(f'make A ({hex(id(self))})')

    def foo(self) -> None:
        print(f'A ({hex(id(self))}) foo')


class B:
    def __init__(self) -> None:
        print(f'make B ({hex(id(self))})')


B.bar = A.foo

b: B = B()  # prints “make B (0x7efc04c67f10)” (or another id)
B.bar(b)    # prints “A (0x7efc04c67f10) foo” (same id, no error)
b.bar()     # same result as before, no error

相反,以下代码不起作用:

from PyQt6.QtCore import QDateTime

QDateTime.toPython = QDateTime.toPyDateTime
t: QDateTime = QDateTime.currentDateTime()
QDateTime.toPython(t)  # no error
t.toPython()           # raises TypeError

推荐答案

这是由于PyQt和PySide之间的实现差异造成的.在前者中,大多数类的方法都是围绕C函数的薄型包装,这些C函数没有实现descriptor protocol(也就是说,它们没有__get__方法).因此,在这方面,它们相当于内置函数,比如len:

>>> type(len)
<class 'builtin_function_or_method'>
>>> type(QtCore.QDateTime.toPyDateTime) is type(len)
True
>>> hasattr(QtCore.QDateTime.toPyDateTime, '__get__')
False

相比之下,大多数PySide方法do实现描述符协议:

>>> type(QtCore.QDateTime.toPython)
<class 'method_descriptor'>
>>> hasattr(QtCore.QDateTime.toPython, '__get__')
True

这意味着,如果逆转兼容性修复,它将按预期工作:

>>> from PySide2 import QtCore
QtCore.QDateTime.toPyDateTime = QtCore.QDateTime.toPython
>>> QtCore.QDateTime.currentDateTime().toPyDateTime()
datetime.datetime(2022, 4, 29, 11, 52, 51, 67000)

然而,如果您想保持当前的命名方案,使用包装函数(例如lambda)基本上是最好的 Select .所有用户定义的Python函数都支持描述符协议,这就是为什么使用简单用户定义类的示例的行为与预期一致.唯一可以建议的改进是使用partialmethod.这将节省编写一些锅炉板代码的时间,并具有提供更多信息的错误消息的额外好处:

>>> QtCore.QDateTime.toPython = partialmethod(QtCore.QDateTime.toPyDateTime)
>>> d = QtCore.QDateTime.currentDateTime()
>>> d.toPython()
datetime.datetime(2022, 4, 29, 12, 13, 15, 434000)
>>> d.toPython(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.10/functools.py", line 388, in _method
    return self.func(cls_or_self, *self.args, *args, **keywords)
TypeError: toPyDateTime(self): too many arguments

我想这里剩下的唯一一点是为什么PyQt和PySide在实现上完全不同的问题.你可能得花ask the author of PyQt英镑才能得到一个明确的解释.我的猜测是,这至少部分是出于历史原因,因为PyQt的存在时间比PySide长得多——但毫无疑问,还有其他几个技术方面的考虑.

Python相关问答推荐

如何使用没有Selenium的Python在百思买着陆页面上处理国家/地区 Select ?

使用scipy. optimate.least_squares()用可变数量的参数匹配两条曲线

使用SciPy进行曲线匹配未能给出正确的匹配

即使在可见的情况下也不相互作用

使用索引列表列表对列进行切片并获取行方向的向量长度

在Python中管理打开对话框

通过pandas向每个非空单元格添加子字符串

两个pandas的平均值按元素的结果串接元素.为什么?

Streamlit应用程序中的Plotly条形图中未正确显示Y轴刻度

当我try 在django中更新模型时,模型表单数据不可见

UNIQUE约束失败:customuser. username

如何从列表框中 Select 而不出错?

在Admin中显示从ManyToMany通过模型的筛选结果

Gekko中基于时间的间隔约束

比Pandas 更好的 Select

在二维NumPy数组中,如何 Select 内部数组的第一个和第二个元素?这可以通过索引来实现吗?

查看pandas字符列是否在字符串列中

如何在Python中将超链接添加到PDF中每个页面的顶部?

如何使用matplotlib查看并列直方图

大型稀疏CSR二进制矩阵乘法结果中的错误