在旧式Python类中使用属性会造成问题吗
这是个很简单的问题。我在很多地方看到提到,老式类上使用属性应该不行,但显然Qt类(通过PyQt4)不是新式的,而且我正在使用的代码中有几个类上有属性(据我所知,这段代码没有出现任何问题)。
我遇到了一个叫pyqtProperty的函数,但我找不到相关的文档。请问在这种情况下,它会是个不错的替代方案吗?
3 个回答
至少在PyQt4.5中,Qt类确实是新式对象,这可以从它们的方法解析顺序看出来:
from PyQt4 import QtGui
print QtGui.QWidget.__mro__
(<class 'PyQt4.QtGui.QWidget'>, <class 'PyQt4.QtCore.QObject'>, <type 'sip.wrapper'>, <class 'PyQt4.QtGui.QPaintDevice'>, <type 'sip.simplewrapper'>, <type 'object'>)
根据我的经验,Python的排序功能在PyQt4对象上运行得很好。我不确定PyQt4是否明确支持这些功能,或者是否有一些隐藏的问题,但我从来没有见过它们出错。下面是一个使用PyQt 4.4和Python 2.5的例子:
from PyQt4.QtCore import QObject
class X( QObject ):
def __init__(self):
self.__x = 10
def get_x(self):
return self.__x
def set_x(self, x):
self.__x = x
x = property(get_x, set_x)
x = X()
print x.x # Should be 10
x.x = 30
print x.x # Should be 30
pyqtProperty
是为了让我们可以使用Qt的属性系统,这个系统和Python的属性系统是不一样的。Qt的属性可以从Qt的C++类中进行检查(而原生的Python属性则不能),并且Qt用这些属性来支持他们的Qt Designer表单编辑器和Qt Creator集成开发环境(IDE)。这些属性允许我们在运行时检查状态,这在Python中是很常见的,但在C++中就比较少见。总的来说,Qt为C++提供了一些动态语言的特性,而这并不是PyQt唯一提供多种方式来实现同一功能的地方(比如字符串、字典、文件输入输出等等)。对于大多数选择,我的主要建议是选择一种方式并坚持使用,以避免出现不兼容的问题。我个人更倾向于使用Python的方式,因为Python对我的工作来说更重要。如果你打算将PyQt的某些功能移植回C++ Qt,那么你可能会更喜欢Qt版本的功能,而不是Python版本的。
属性之所以能正常工作,是因为QObject有一个特殊的元类来处理这些属性。看看这个小变动,基于@quark的代码……:
from PyQt4.QtCore import QObject
def makec(base):
class X( base ):
def __init__(self):
self.__x = 10
def get_x(self):
print 'getting',
return self.__x
def set_x(self, x):
print 'setting', x
self.__x = x
x = property(get_x, set_x)
print 'made class of mcl', type(X), issubclass(type(X), type)
return X
class old: pass
for base in (QObject, old):
X = makec(base)
x = X()
print x.x # Should be 10
x.x = 30
print x.x # Should be 30
运行这个代码会输出:
made class of mcl <type 'PyQt4.QtCore.pyqtWrapperType'> True
getting 10
setting 30
getting 30
made class of mcl <type 'classobj'> False
getting 10
30
你能看到区别吗?在那个真正是旧式类的例子中,也就是第二次创建的那个类,元类是classobj
(这不是type的子类),所以属性不能正常工作(给x.x
赋值时会绕过属性,之后再获取x.x
时也看不到属性了)。而在第一个例子,也就是Qt的情况,元类是不同的,它是type的子类(所以说这个类“不是新式的”其实并不准确!),因此一切都能正常运作。