Search code examples
pythonwxpythonconditional-statementsdel

del class with wxpython inside conditional works unexpectedly


I am trying to delete an instance of a class when a condition is done. But I am having issues, because it´s being deleted before it enters the condition. I don´t know what´s happening... The code uses wxpython with some buttons for deleting ítems, so I build the buttons correctly on init but when I try to delete an ítem, before it reaches the first conditional, it seems to be deleted by the las conditional, that should be never done before. So I don´t know where the problem comes from... The error I get when i press the button 'deleteitem' for the first time is:

'local variable 'T' referenced before assignment' (in 6th the line:... if T.items>0:)

But if I delete the last line del(T) it doesn´t give any error.

Here goes the basic code:

class Test(object):
    def __init__(self):
        self.items=8

T=Test()



if button.GetName()=='deleteitem': 
    if T.items>0:
        T.items-=1
        if T.items<0:
            del(T)

EDITED:

OK, as the example I posted firstly can work, here goes the code that doesn´t work:

import wx

class Test(object):
    def __init__(self):
        self.items=8

T=Test()

class MyFrame(wx.Frame):

    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, -1, title,
                          pos=(150, 150), size=(350, 200))

        self.btn = wx.Button(self, -1, "Press to delete Item, current Items: "+str(T.items))
        self.Bind(wx.EVT_BUTTON, self.OnButton, self.btn)


    def OnButton(self, evt):
        print 'Current Items: '+str(T.items)
        self.btn.SetLabel('Press to delete Item, current Items: '+str(T.items))
        if T.items>0:
            T.items-=1
            if T.items==0:
                del(T)


class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, "Simple wxPython App")
        frame.Show(True)
        return True

app = MyApp()
app.MainLoop()

FINAL WORKING CODE:

import wx

class Test(object):
    def __init__(self):
        self.items=8

class MyFrame(wx.Frame):

    def __init__(self, parent, title):
        self.T=Test()
        wx.Frame.__init__(self, parent, -1, title,
                          pos=(150, 150), size=(350, 200))

        self.btn = wx.Button(self, -1, "Press to delete Item, current Items: "+str(self.T.items))
        self.Bind(wx.EVT_BUTTON, self.OnButton, self.btn)


    def OnButton(self, evt):
        if self.T.items>0:
            self.T.items-=1
            if self.T.items==0:
                del(self.T)
                self.btn.SetLabel('Deleted instance T')
            else:
                self.btn.SetLabel('Press to delete Item, current Items: '+str(self.T.items))
                print 'current Items: '+str(self.T.items)

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, "Simple wxPython App")
        frame.Show(True)
        return True

app = MyApp()
app.MainLoop()

Solution

  • You are leaving out some relevant code because this code:

    class Test(object):
        def __init__(self):
            self.items=8
    
    T=Test()
    
    
    
    if True: 
        if T.items>0:
            T.items-=1
            if T.items<0:
                del(T)
    

    executes without error.

    In any case, it sounds like your code is some variation of Variable scope in nested functions.

    Response to new code:

    As far as I can tell, del localizes a variable:

    Example 1:

    class Test(object):
        def __init__(self):
            self.items=8
    
    T = Test()
    
    class Dog(object):
        def dostuff(self):
            print 'executing dostuff()'
            if T.items > 10:  #This will never be True
                T
    
    Dog().dostuff()
    
    --output:--
    executing dostuff()
    

    Example 2:

    class Test(object):
        def __init__(self):
            self.items=8
    
    T = Test()
    
    class Dog(object):
        def dostuff(self):
            print 'executing dostuff()'
            if T.items > 10:  #This will never be True
                del T
    
    
    Dog().dostuff()
    
    --output:--
    executing dostuff()
    Traceback (most recent call last):
      File "1.py", line 14, in <module>
        Dog().dostuff()
      File "1.py", line 10, in dostuff
        if T.items > 10:
    UnboundLocalError: local variable 'T' referenced before assignment
    

    So it looks like the parser marks T as a local variable inside the dostuff() function--because you can only del local names (unless you declare T to be global inside dostuff() ). As a result, python won't look outside the dostuff() function for the value of T.

    Therefore, another solution(not recommended) would be to do this:

    class Test(object):
        def __init__(self):
            self.items=8
    
    T = Test()
    
    class Dog(object):
        def dostuff(self):
            global T  #<===HERE
            print 'executing dostuff()'
    
            if T.items > 10:
                del T
    
    
    Dog().dostuff()
    
    --output:--
    executing dostuff()
    

    To solve your problem, I would add the following to the end of your __init__() function:

    self.T = Test()
    

    Or, you could pass T as an argument to __init__(). It's generally considered terrible program design to have functions inside a class manipulating global variables.