I found a case where getattr(self, "x")
behaves different from self.x
. Sorry about the length of the post - I didn't know how to reproduce the behavior without the PySide2 around. So with this example.qml
file:
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
}
}
and this example.py
file:
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_())
using Python 3.7.
Why is the getattr
(2) version not working?
Note that I need a version with the getattr
because I want to decorate other classes. In that case it is not possible to use the dot-calling version.
In the documentation, there is an example that claims both to be the same. I can imagine that maybe the C++ code of PySide2 causes the difference. However I don't know how to proceed from here.
Because you are using double-underscore name mangling.
From 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.
You probably don't need to use double-underscore name mangling so just don't use it.