【问题标题】:Limit number of class instances with python使用python限制类实例的数量
【发布时间】:2012-07-12 18:40:05
【问题描述】:

Μy Mainclass 像这样创建一个简单的QmainWindows

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

        self.initUI()

    def initUI(self):
        self.show()

在我的文件末尾,我这样启动它:

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


if __name__ == '__main__':
    main()

我的问题是每次我获取它时,它都会启动一个新窗口。 我想知道是否有一种方法可以检测我的脚本中是否存在以前的类实例(以便我关闭旧的或避免启动新的),或任何其他解决方案?

另外,当我用 py2exe 编译我的代码时,我在 Windows 上的 .exe 文件也有同样的问题;它每次都会启动一个新窗口。我可以在 setup.py 中添加一些内容以使 Windows 不这样做吗?

有可能吗,如果可以,怎么办?

注意:我使用的是 Windows 7 64bit 与 eclipse 编译。

【问题讨论】:

  • 这些是独立的进程吗?
  • 所有都在同一个file.py中,我正在尝试将def main放在一个单独的file.py中,但这是一种制作单独进程的方法吗?

标签: python class pyqt instance py2exe


【解决方案1】:

有几种方法可以做到这一点,您可以使用 Class 属性来存储所有实例——如果您这样做,您可能希望通过 weakref 模块将它们存储为弱引用以防止垃圾问题收集:

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

这有点难看。您可能还想考虑使用某种工厂(有条件地)创建一个新实例。这种方法比较通用。

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

【讨论】:

  • @Pooya -- 谢谢。我其实用过这种东西。我将数据文件(每个约 .5 GB)抽象在一个类中,该类在读取数据时存储数据。我的工厂获取文件名,确定它是否已经打开,如果存在,则返回打开的数据文件的句柄,否则我创建一个新的数据文件。它工作得很好。引用都作为弱引用存储在工厂中,这样我的 500mb 数据就不会在我关闭文件后留下。
  • 太棒了,你是如何为你的数据文件实现weakref的?
  • @Pooya -- 使用 weakref.ref 更新了 Factory 示例。在我的数据文件示例中,我使用字典而不是列表来存储产品。然后检查它的数据文件是否仍然存在是微不足道的。 datafile=d[fname] if ((fname in d) and (d[fname]() is not None)) else DataFileObject(fname,*args,**kwargs)
  • 我尝试了第一个解决方案,它应该可以工作,但是,我使用的是 Eclipse,是否有可能 Eclipse 每次资源类并忘记类属性时都会创建一个新进程?跨度>
  • @Ennakard -- Eclipse 应该没关系(如果有,这是他们需要修复的一个巨大错误)。在您的问题中,您说“所以我的问题是,每次我采购它”——“每次我采购它”是什么意思?
【解决方案2】:

您可以通过添加计数器来限制要在代码中创建的实例数量:

class A(object):
 ins = 0 # This is a static counter
 def __init__(self):
  if A.ins >= 1: # Check if the number of instances present are more than one. 
   del self
   print "Failed to create another instance" #if > 1, del self and return.
   return
  A.ins += 1
  print "Success",str(self)

尝试通过以下方式运行:

lst = []
for i in range(1,101):
 a=A()
 lst.append(a)

【讨论】:

    【解决方案3】:

    你可以独占一个套接字

    import socket
    try:    
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    except:
        "Network Error!"
    
    s.settimeout(30)
    try:
        s.connect(('localhost' , 123))
    except:
        "could not open...already in use socket(program already running?)"
    

    不知道这是否是一个好方法,但我过去曾使用过它并解决了这个问题

    这是为了防止在程序已经运行时启动程序,而不是从生成多个窗口的单个脚本中启动新窗口...

    【讨论】:

    • 为什么是-1?如果你要给我一个负分,请评论主要缺点......这甚至适用于使用 py2exe 的冻结实例......当然你需要选择一个通常打开的端口......[编辑]啊我没有注意到他正在从同一个脚本中启动多个实例......在这种情况下,我相信有更好的方法来做到这一点
    • 可以工作,但是 Windows 7 中的套接字很糟糕,你必须在防火墙中添加一个规则才能使用你想要的每个套接字。
    • 默认情况下有一些是打开的...如果您选择其中一个就可以了(我使用的那个是 3322466)并且从您的本地主机打开比从外部打开更多连接
    【解决方案4】:

    使用类变量:

    class mcManageUiC(QtGui.QMainWindow):
        singleton = None
        def __init__(self):
            if not mcManageUiC.singleton: #if no instance yet
                super(mcManageUiC, self).__init__()
    
                self.initUI()
                ...
                mcManageUiC.singleton = self
            else: 
                ...
    
    
        def initUI(self):
            self.show()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-01
      • 1970-01-01
      相关资源
      最近更新 更多