Search code examples
pythonclasspyqtinstancepy2exe

Limit number of class instances with python


Μy Mainclass creates a simple QmainWindows like this:

class mcManageUiC(QtGui.QMainWindow):
    def __init__(self):
        super(mcManageUiC, self).__init__()

        self.initUI()

    def initUI(self):
        self.show()

And at the end of my file I launch it like this:

def main():
    app = QtGui.QApplication(sys.argv)
    renderManagerVar = mcManageUiC()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

My problem is that each time i source it, it launches a new window. I would like to know if there is a way to detect existence of previous class instance in my script (so that I close the old one or avoid launching a new one), or any other solutions?

Also, when compiling my code with py2exe, same problem with my .exe file on Windows; it launchs a new window every time. Could i add something in the setup.py for Windows to not act like this?

Is it possible, if yes then how?

Note: I'm using Windows 7 64bit compiling with eclipse.


Solution

  • There are a couple ways to do this, you can use a Class attribute to store all the instances -- If you do it this way, you may want to store them as weak references via the weakref module to prevent issues with garbage collecting:

    class MyClass(object):
        _instances=[]
        def __init__(self):
            if(len(self._instances) > 2):
                self._instances.pop(0).kill() #kill the oldest instance
            self._instances.append(self)
    
        def kill(self):
            pass #Do something to kill the instance
    

    This is a little ugly though. You might also want to consider using some sort of Factory which (conditionally) creates a new instance. This method is a little more general.

    import weakref
    class Factory(object):
         def __init__(self,cls,nallowed):
             self.product_class=cls  #What class this Factory produces
             self.nallowed=nallowed  #Number of instances allowed
             self.products=[]
    
         def __call__(self,*args,**kwargs):
             self.products=[x for x in self.products if x() is not None] #filter out dead objects
             if(len(self.products) <= self.nallowed):
                 newproduct=self.product_class(*args,**kwargs)
                 self.products.append(weakref.ref(newproduct))
                 return newproduct
             else:
                 return None
    
    #This factory will create up to 2 instances of MyClass
    #and refuse to create more until at least one of those 
    #instances have died.
    factory=Factory(MyClass,2)   
    i1=factory("foo","bar")      #instance of MyClass
    i2=factory("bar","baz")      #instance of MyClass
    i3=factory("baz","chicken")  #None