为什么 getattr(self, "x") 与本例中的 self.x 不同?
Why is getattr(self, "x") not the same as self.x in this example?
我发现 getattr(self, "x")
的行为与 self.x
不同的情况。抱歉 post 的长度 - 我不知道如何在没有 PySide2 的情况下重现该行为。所以有了这个 example.qml
文件:
import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
import QtQuick.Controls.Material 2.3
ApplicationWindow {
id: applicationWindow
Material.theme: Material.Dark
title: qsTr("Test Invoke")
visible: true
width: 600
height: 500
Slider {
id: slider1
x: 69
y: 215
value: Manager.xyz
property bool updateValueWhileDragging: true
onMoved: Manager.xyz = value
}
}
和这个 example.py
文件:
import sys
import os
from PySide2.QtCore import Qt, QObject, Signal, Slot, Property
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtWidgets import QSlider, QPushButton, QCheckBox
class Manager(QObject):
xyz_slot = Signal()
def __init__(self):
QObject.__init__(self)
self.__xyz = None
self.xyz_slot.connect(self.on_xyz_changed)
self.xyz = 0.3
@Property(float, notify=xyz_slot) # (6)
def xyz(self):
# (1) This works
# return self.__xyz
# (2) This doesn't work and produces the error:
# Error: 'Manager' object has no attribute '__xyz'
return getattr(self, "__xyz")
@xyz.setter
def set_xyz(self, val):
if self.__xyz == val:
return
self.__xyz = val
self.xyz_slot.emit()
@Slot()
def on_xyz_changed(self):
print(self.__xyz)
if __name__ == "__main__":
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
manager = Manager()
ctx = engine.rootContext()
ctx.setContextProperty("Manager", manager)
engine.load('example.qml')
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
使用 Python 3.7.
为什么 getattr
(2) 版本不工作?
请注意,我需要一个带 getattr
的版本,因为我想装饰其他 类。在那种情况下,不可能使用点调用版本。
在the documentation中,有一个例子声称两者是一样的。我可以想象可能是 PySide2 的 C++ 代码导致了差异。但是我不知道如何从这里开始。
因为您正在使用双下划线名称修改。
来自the docs
Notice that code passed to exec()
or eval()
does not consider the classname of the invoking class to be the current class; this is similar to the effect of the global statement, the effect of which is likewise restricted to code that is byte-compiled together. The same restriction applies to getattr()
, setattr()
and delattr()
, as well as when referencing __dict__
directly.
您可能不需要使用双下划线名称修饰,所以不要使用它。
我发现 getattr(self, "x")
的行为与 self.x
不同的情况。抱歉 post 的长度 - 我不知道如何在没有 PySide2 的情况下重现该行为。所以有了这个 example.qml
文件:
import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
import QtQuick.Controls.Material 2.3
ApplicationWindow {
id: applicationWindow
Material.theme: Material.Dark
title: qsTr("Test Invoke")
visible: true
width: 600
height: 500
Slider {
id: slider1
x: 69
y: 215
value: Manager.xyz
property bool updateValueWhileDragging: true
onMoved: Manager.xyz = value
}
}
和这个 example.py
文件:
import sys
import os
from PySide2.QtCore import Qt, QObject, Signal, Slot, Property
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtWidgets import QSlider, QPushButton, QCheckBox
class Manager(QObject):
xyz_slot = Signal()
def __init__(self):
QObject.__init__(self)
self.__xyz = None
self.xyz_slot.connect(self.on_xyz_changed)
self.xyz = 0.3
@Property(float, notify=xyz_slot) # (6)
def xyz(self):
# (1) This works
# return self.__xyz
# (2) This doesn't work and produces the error:
# Error: 'Manager' object has no attribute '__xyz'
return getattr(self, "__xyz")
@xyz.setter
def set_xyz(self, val):
if self.__xyz == val:
return
self.__xyz = val
self.xyz_slot.emit()
@Slot()
def on_xyz_changed(self):
print(self.__xyz)
if __name__ == "__main__":
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
manager = Manager()
ctx = engine.rootContext()
ctx.setContextProperty("Manager", manager)
engine.load('example.qml')
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
使用 Python 3.7.
为什么 getattr
(2) 版本不工作?
请注意,我需要一个带 getattr
的版本,因为我想装饰其他 类。在那种情况下,不可能使用点调用版本。
在the documentation中,有一个例子声称两者是一样的。我可以想象可能是 PySide2 的 C++ 代码导致了差异。但是我不知道如何从这里开始。
因为您正在使用双下划线名称修改。
来自the docs
Notice that code passed to
exec()
oreval()
does not consider the classname of the invoking class to be the current class; this is similar to the effect of the global statement, the effect of which is likewise restricted to code that is byte-compiled together. The same restriction applies togetattr()
,setattr()
anddelattr()
, as well as when referencing__dict__
directly.
您可能不需要使用双下划线名称修饰,所以不要使用它。