PyQt v5.11 需要注意的事情

   TLS支持

对传输层安全性(TLS)的支持变得越来越重要,特别是在移动平台上,其中应用程序通常是基于云的服务器的前端。由于Python和Qt都实现了支持TLS的不同API,因此PyQt应用程序可以选择使用哪种API。这在部署应用程序时尤其重要,因为支持可能必须包含在应用程序本身中或内置于应用程序本身中。

理想情况下,将使用目标提供的TLS实现(例如,Windows上的CryptoAPI,macOS和iOS上的安全传输)。这意味着安全更新(包括证书更新)将由目标操作系统的供应商处理,并且可以被应用程序忽略。不幸的是,没有常见的TLS API。

Python支持在OpenSSL v1.0中实现的TLS API(从Python v3.7.0开始,OpenSSL v1.1)。在Linux上,实际上是供应商提供的API,因此Python可以使用它。但是,在Windows和macOS上,标准Python二进制安装程序包含OpenSSL库的副本。该问题的解决方案是PEP 543的主题, 但尚未实施。

Qt支持macOS和iOS上的本机TLS实现,但在其他平台上(Linux除外),部署的应用程序必须包含它自己的OpenSSL实现。

   枚举

版本5.11中的新功能。

PyQt(或者说SIP)使用专用的Python类型包装C / C ++枚举。枚举的成员在与枚举本身相同的范围内可见。

Qt正在越来越多地使用C ++ 11范围的枚举,并且对它们的支持被添加到SIP v4.19.4中。Scoped枚举使用标准enum.EnumPython类型实现。在这种情况下,枚举的成员仅在枚举的范围内可见。

可见性的差异是不幸的,因为它需要Python程序员了解底层C ++枚举的本质。

使用SIP v4.19.9,传统C / C ++枚举的成员现在也可以在枚举范围内看到。强烈建议始终通过指定枚举的范围来引用枚举成员。PyQt6不允许任何其他访问方法。

   溢出检查

在将数字Python对象转换为C ++类型时,PyQt(或更确切地说SIP)不检查溢出。更糟糕的是,溢出的值是未定义的 - 不能假设过多的高阶位被简单地丢弃。

应用程序可以通过调用该sip.enableoverflowchecking()函数随时启用(并随后禁用)溢出检查。

计划在某些未来版本的PyQt中默认启用溢出检查。

   退出时崩溃

当Python解释器离开 作用域时(例如,当它从函数返回时),它可能会垃圾收集该作用域的所有本地对象。它的完成顺序实际上是随机的。从理论上讲,这可能会导致问题,因为它可能意味着任何包装的Qt实例的C ++析构函数都是按照Qt不期望的顺序调用的,并且可能导致崩溃。

但是,实际上,当应用程序终止时,这可能只是一个问题。例如,最好只在销毁所有小部件后销毁任何QApplication实例。

作为一种减轻这种可能性的方法,PyQt5确保在应用程序终止时不调用任何模块级对象的析构函数。这意味着遵循以下模式的代码在退出时不太可能崩溃:

if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = QWidget()
    w.show()

    app.exec()

另一种常见模式(以及使用setuptool入口点时需要的模式)是上面的代码放在一个单独的函数中,通常称为main()。然后,当函数返回时会导致问题,因为可能以错误的顺序调用QApplication和 QWidget实例的析构函数。为尽量减少发生这种情况的可能性,建议采用以下模式:

app = None

def main():
    global app
    app = QApplication(sys.argv)

    w = QWidget()
    w.show()

    app.exec()

if __name__ == '__main__':
    main()

QWidget的时候析构函数被调用 main()的回报,但在模块级参考 QApplication的所有被调用的实例将阻止其析构函数。

   关键字参数

PyQt5支持使用关键字参数作为可选参数。虽然PyQt5和Qt文档可能表明参数具有特定名称,但您可能会发现PyQt5实际上使用了不同的名称。这是因为参数的名称不是Qt API的一部分,并且在命名类似参数的方式上存在一些不一致。不同版本的Qt可能会为参数使用不同的名称,这些名称不会影响C ++ API,但会破坏Python API。

PyQt5为所有类,函数和方法生成的文档字符串将包含正确的参数名称。在PyQt5的未来版本中,文档也将保证包含正确的参数名称。

   Python字符串,Qt字符串和

Qt使用QString类来表示Unicode字符串,并使用它 QByteArray来表示字节数组或字符串。在Python v3中,相应的本机对象类型是strbytes。在Python v2中,相应的本机对象类型是unicodestr

PyQt5尽力在各种类型的对象之间自动转换。必要时可以轻松进行显式转换。

在某些情况下,PyQt5不会执行自动转换,因为有必要区分不同的重载方法。

对于Python v3,默认情况下会进行以下转换。

  • 如果Qt期望(或版本),那么PyQt5将接受 仅包含ASCII字符,a ,a 或实现缓冲协议的Python对象。char*conststrbytesQByteArray
  • 如果Qt期望一个char(或一个const版本),那么PyQt5将接受与之相同的类型,并且还要求提供单个字符。char *
  • 如果Qt期望a 或(或 版本),那么PyQt5将接受a 。signed char *unsigned char *constbytes
  • 如果Qt期望一个或一个(或一个 版本),那么PyQt5将接受长度为1的a。signed charunsigned charconstbytes
  • 如果Qt期望a QString那么PyQt5将接受a str,a bytes 只包含ASCII字符,a QByteArrayNone
  • 如果Qt期望一个,QByteArray那么PyQt5也会接受一个bytes
  • 如果Qt期望a QByteArray那么PyQt5也会接受str只包含Latin-1字符的那个。

对于Python v2,默认情况下会进行以下转换。

  • 如果Qt的期望一个,或一个(或 版本),那么PyQt5将接受的是只包含ASCII字符,一,一个,或者一个Python实现该缓冲协议对象。char *signed char *unsigned char *constunicodestrQByteArray
  • 如果Qt的期望一个char,或一个(或 版本),那么PyQt5将接受相同类型为, 和,并且还需要一个单独的字符设置。signed charunsigned charconstchar *signed char *unsigned char *
  • 如果Qt期望a QString那么PyQt5将接受a unicode,a str 只包含ASCII字符,a QByteArrayNone
  • 如果Qt期望QByteArray然后PyQt5将接受a str
  • 如果Qt期望a QByteArray那么PyQt5将接受unicode仅包含Latin-1字符的那个。

请注意,Python v2和v3之间的不同行为是由于v3减少了对缓冲区协议的支持。

历史上QString区分空字符串和空字符串。当前版本的Qt将空字符串视为空字符串,但PyQt5应用程序可能会调用其他C ++代码来保持区别。因此PyQt5将转换None为null QString。不进行反向转换,将null和empty QString都转换为空(即零长度)Python字符串。

   垃圾收集

C ++不会垃圾收集未引用的类实例,而Python会这样做。在下面的C ++片段中,即使第一个不能再从程序中引用,也存在两种颜色:

col = new QColor();
col = new QColor();

在相应的Python片段中,第二种颜色在第二种颜色被分配时被销毁col

col = QColor()
col = QColor()

在Python中,每种颜色必须分配给不同的名称。通常这是在类定义中完成的,因此代码片段将类似于:

self.col1 = QColor()
self.col2 = QColor()

有时,Qt类实例将维护指向另一个实例的指针,并最终调用该第二个实例的析构函数。最常见的示例是QObject(及其任何子类)保持指向其子节点的指针,并将自动调用其析构函数。在这些情况下,相应的Python对象也将保留对相应子对象的引用。

因此,在以下Python片段中,第一个 QLabel在分配第二个QLabel时不会被销毁,lab因为父QWidget 仍然具有对它的引用:

parent = QWidget()
lab = QLabel("First label", parent)
lab = QLabel("Second label", parent)

   多重继承

不可能从多个Qt类定义一个新的Python类子类。例外是专门用作mixin类的类,例如实现Qt接口的那些(如QQmlParserStatus)。

   访问受保护的成员函数

如果未从Python创建C ++类的实例,则无法访问该实例的受保护成员函数。尝试这样做会引发Python异常。此外,永远不会调用与实例的虚拟成员函数对应的任何Python方法。

 NoneNULL

在整个PyQt5中,None可以NULL在底层C ++代码可接受的任何地方指定该值。

同样,无论何时由底层C ++代码返回它都会NULL转换为None

   支持void *

PyQt5(实际上是SIP)将值表示为sip.voidptr类型的对象。这些值通常用于在不同的Python模块之间传递外部对象的地址。为了简化这一过程,只要需要sip.voidptr,就可以使用Python整数(或Python可以转换为整数的任何东西)。void *

可以使用int()内置函数将sip.voidptr转换为Python整数 。

可以使用sip.voidptr将sip.voidptr转换为Python字符串 asstring()。该asstring()方法采用可选的整数参数,该参数是以字节为单位的数据长度。

也可以通过调用其setsize() 方法给sip.voidptr一个大小(即,指向的内存块的大小)。如果它有一个大小,那么它也能够支持Python的缓冲协议,并且行为类似于Python memoryview对象,因此可以将内存块视为可变的字节列表。它还意味着Python结构模块可用于在内存,内存映射文件或共享内存中解压缩和打包二进制数据结构。

猜你喜欢

转载自blog.csdn.net/Yuyh131/article/details/84648849
今日推荐