Python Forum
[PyQt] change self.var in a function
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] change self.var in a function
#1
import sys,os,re
import numpy as np
import PI_GUI_App_Map as pgam
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QLineEdit, QMessageBox ,QWidget,QGridLayout,QPushButton,QLabel,QTextBrowser,QDesktopWidget
from PyQt5.QtGui import *
from PyQt5 import QtCore
from PyQt5.QtCore import Qt


'''################################CLASS###################################'''
class appmap(pgam.Ui_Form):
    
##########################################################################
    def __init__(self,MainWindow):
        self.setupUi(MainWindow)
        self.main(MainWindow)
        self.xlist=[] '''HERE'''
        self.ylist=[] '''HERE'''
        self.zlist=[] '''HERE'''
##########################################################################
    def main(self,MainWindow):
        MainWindow.setWindowTitle('Approach Curve-Map')

        self.lineEdit_xp.editingFinished.connect(
            lambda: self.list_read(widget=self.lineEdit_xp,tlist=self.xlist)) '''HERE'''
        self.lineEdit_yp.editingFinished.connect(
            lambda: self.list_read(widget=self.lineEdit_yp,tlist=self.ylist)) '''HERE'''
        self.lineEdit_zp.editingFinished.connect(
            lambda: self.list_read(widget=self.lineEdit_zp,tlist=self.zlist)) '''HERE'''

        self.lineEdit_xp.editingFinished.connect(self.sample_stat)
        self.lineEdit_yp.editingFinished.connect(self.sample_stat)
        self.lineEdit_zp.editingFinished.connect(self.sample_stat)

##########################################################################
    def list_read(self,widget,tlist,ty=int): '''HERE'''
        try:
            string=widget.text()
            self.res=[]
            element=string.split(",")
            sets=[]
            num=[]
            for ele in element:
                if '(' in ele:
                    sets.append(ele)           
                else:
                    num.append(ty(ele))
            self.res+=list(map(ty, num))
            for i in sets:
                numset=re.findall(r'[(](.*?)[)]', i)
                rangepara=numset[0].split(' ')
                rangepara=list(map(int, rangepara))
                self.res+=np.arange(rangepara[0],rangepara[1]+1,rangepara[2]).tolist()
            self.res.sort()
            tlist=self.res '''HERE'''
            print(tlist) '''HERE'''
            print(self.xlist) '''HERE'''
            print(self.ylist) '''HERE'''
            print(self.zlist) '''HERE'''
        except KeyboardInterrupt:
            sys.exit(app.exec_())
        except Exception:
            self.errormsg=QMessageBox()
            self.errormsg.setIcon(QMessageBox.Critical)
            self.errormsg.setText('Potentially input error, please check your inputs')
            self.errormsg.setStandardButtons(QMessageBox.Ok)
            self.errormsg.setWindowTitle('Error')
            self.errormsg.show()
        print(tlist)
################################
    def sample_stat(self):
        try:
            num2d=len(self.xlist) * len(self.ylist)
            num3d=len(self.xlist) * len(self.ylist) * len(self.zlist)
            print(len(self.xlist) , len(self.ylist),len(self.zlist) )
            self.lineEdit_total_2d.setText(str(num2d))
            self.lineEdit_total_exp.setText(str(num3d))
        except KeyboardInterrupt:
            sys.exit(app.exec_())
        except Exception:
            pass

if __name__=='__main__':
    os.system('python -m PyQt5.uic.pyuic PI_GUI_App_Map.ui -o PI_GUI_App_Map.py')
    app = QApplication(sys.argv)
    win=QWidget()
    ui=appmap(win)
    win.show()
    sys.exit(app.exec_())
All the related parts have '''HERE'''

I initialised three class vars (self.xlist,self.ylist,self.zlist)

they are passed to one function through a para (tlist) from DIFFERENT widget signals
but the para of the function (tlist) does not actually change the vars of the class.

is there a way to?

Thanks!!!
Reply
#2
The lists are empty and will remain so until you fill them.
Reply
#3
This is what you are trying to do:
class MyClass:
    def __init__(self, alist):
        self.alist = alist

    def func(self, list_arg):
        list_arg= ['a', 'new', 'list']

    def __str__(self):
        return str(self.alist)

obj = MyClass(['This', 'is', 'a', 'list'])
print(obj)
obj.func(obj.alist)
print(obj)
Output:
['This', 'is', 'a', 'list'] ['This', 'is', 'a', 'list']
Setting the value of list_arg in func() does nothing to alist because alist and list_arg are not the same variable. They reference the same list object (initially), but they are not the same variable. Changing one does not affect the other.

If you really need your listread() method to change the xlist variable you could pass the attribute name and use that to set the xlist attribute.
class MyClass:
    def __init__(self, alist):
        self.alist = alist

    def func(self, list_attr):
        self.__setattr__(list_attr, ['a', 'new', 'list'])  # Set attribute using the attribute name

    def __str__(self):
        return str(self.alist)

obj = MyClass(['This', 'is', 'a', 'list'])
print(obj)
obj.func('alist')  # Pass the attribute name
print(obj)
Output:
['This', 'is', 'a', 'list'] ['a', 'new', 'list']
I can't say how much I think this is a bad idea, but it can be done. Lucky for you, you don't have to resort to such ugly code. You don't really have any reason to change the list variable. You are really only interested in what the list contains.
class MyClass:
    def __init__(self, alist):
        self.alist = alist

    def func(self, list_arg):
        list_arg[:] = ['a', 'new', 'list']  # Modify the list, don't make a new list

    def __str__(self):
        return str(self.alist)

obj = MyClass(['This', 'is', 'a', 'list'])
print(obj)
obj.func(obj.alist)
print(obj)
Output:
['This', 'is', 'a', 'list'] ['a', 'new', 'list']
This code works because we are changing the list object, not the instance variable that references the list object. It can be confusing at first, but variables are not the thing they reference. This can be shown with a simple example:
a = ['a', 'list']
b = a
print(a, b)
b = 12
print(a, b)
Output:
['a', 'list'] ['a', 'list'] ['a', 'list'] 12
Changing "b" did nothing to "a". The list that "a" references is unchanged even though the variable "b", which referenced the same list, has changed.

Because lists are mutable (can be changed), you can make it look like changing "b" changes "a".
a = ['a', 'list']
b = a
print(a, b)
b[:] = ['different', 'contents']
print(a, b)
Output:
['a', 'list'] ['a', 'list'] ['different', 'contents'] ['different', 'contents']
It looks like changing "b" changed the value of "a", but this is not correct. The value of "b" never changed. Instead we changed the list object that is referenced by "b" (and "a"). Since a and b are both looking at the same list, any changes to that list are seen when you reference the list through "a" or "b".
Reply
#4
(Jul-21-2021, 07:36 PM)deanhystad Wrote: This is what you are trying to do:
class MyClass:
    def __init__(self, alist):
        self.alist = alist

    def func(self, list_arg):
        list_arg= ['a', 'new', 'list']

    def __str__(self):
        return str(self.alist)

obj = MyClass(['This', 'is', 'a', 'list'])
print(obj)
obj.func(obj.alist)
print(obj)
Output:
['This', 'is', 'a', 'list'] ['This', 'is', 'a', 'list']
Setting the value of list_arg in func() does nothing to alist because alist and list_arg are not the same variable. They reference the same list object (initially), but they are not the same variable. Changing one does not affect the other.

If you really need your listread() method to change the xlist variable you could pass the attribute name and use that to set the xlist attribute.
class MyClass:
    def __init__(self, alist):
        self.alist = alist

    def func(self, list_attr):
        self.__setattr__(list_attr, ['a', 'new', 'list'])  # Set attribute using the attribute name

    def __str__(self):
        return str(self.alist)

obj = MyClass(['This', 'is', 'a', 'list'])
print(obj)
obj.func('alist')  # Pass the attribute name
print(obj)
Output:
['This', 'is', 'a', 'list'] ['a', 'new', 'list']
I can't say how much I think this is a bad idea, but it can be done. Lucky for you, you don't have to resort to such ugly code. You don't really have any reason to change the list variable. You are really only interested in what the list contains.
class MyClass:
    def __init__(self, alist):
        self.alist = alist

    def func(self, list_arg):
        list_arg[:] = ['a', 'new', 'list']  # Modify the list, don't make a new list

    def __str__(self):
        return str(self.alist)

obj = MyClass(['This', 'is', 'a', 'list'])
print(obj)
obj.func(obj.alist)
print(obj)
Output:
['This', 'is', 'a', 'list'] ['a', 'new', 'list']
This code works because we are changing the list object, not the instance variable that references the list object. It can be confusing at first, but variables are not the thing they reference. This can be shown with a simple example:
a = ['a', 'list']
b = a
print(a, b)
b = 12
print(a, b)
Output:
['a', 'list'] ['a', 'list'] ['a', 'list'] 12
Changing "b" did nothing to "a". The list that "a" references is unchanged even though the variable "b", which referenced the same list, has changed.

Because lists are mutable (can be changed), you can make it look like changing "b" changes "a".
a = ['a', 'list']
b = a
print(a, b)
b[:] = ['different', 'contents']
print(a, b)
Output:
['a', 'list'] ['a', 'list'] ['different', 'contents'] ['different', 'contents']
It looks like changing "b" changed the value of "a", but this is not correct. The value of "b" never changed. Instead we changed the list object that is referenced by "b" (and "a"). Since a and b are both looking at the same list, any changes to that list are seen when you reference the list through "a" or "b".
Thank you very much
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020