使用Python将变量从一个类实例传递到另一个类?

时间:2012-01-15 19:17:38

标签: python class user-interface variables wxpython

我在将一个类实例中定义的变量传递给另一个类实例时遇到了麻烦。我对使用类相对较新,但我理解变量可以通过简单地定义为类实例的一部分(例如在下面的示例中)从一个实例传递到另一个实例。虽然我过去曾使用过这个模型,但我从未试图使用wxPython之类的GUI框架来实现这一目标。

class Foo(object):
    def __init__(self, var):
        self.var = var

class Bar(object):
    def do_something(self, var):
        print var*3

if __name__ == '__main__':
    f = Foo(3)
    b = Bar()
    b.do_something(f.var)

我遇到的问题是wxPython实例似乎是预定义的,不会接受任何其他参数(允许我只传递标题,大小等内容)到类实例。

我面临的另一个问题是我试图通过调用一个对话框窗口来深入传递变量三个类,并从对话框中调用一个单独的类来设计一个工作线程。

所以我的问题是:

  1. 如何将变量从第一个类实例传递到第三个类实例?

  2. 如何覆盖wxPython实例以允许定义其他变量?

  3. 或者,是否可以创建自定义事件处理程序来传递必要的数据?

  4. 澄清......

    我正在使用Python,并且我想我理解使用Classes进行编程的基础知识以及使用Tkinter和wxPython等框架的GUI(在此项目中使用)。我编写了一个主类/实例,它从用户那里获取一些数据,我希望能够传递存储在self.main_instance_var中的信息并将其传递给第二个类/实例(在本例中为Progress Dialog窗口)从第一堂课打来的。

    当我尝试在进度对话框中使用上述模型时,我得到了一个非常无法解释的语法错误('关键字arg之后的非关键字arg')。阻止我进一步将变量从“进度对话框”窗口传递到工作线程。如果我得到了一个异常,那将是一件事,但语法错误,我不明白。请看下面的简短示例:

    class ProgressDialog(wx.Dialog):
    
        def __init__(self, parent, title, myVar):     # Generates syntax error on this line
            super(ProgressDialog, self).__init__(parent=parent, 
                title=title, size=(500, 110))
            self.var = myVar
    

    基本来源(根据要求,抱歉它太脏了):

    import time
    import os, sys, wx
    from ftplib import FTP_TLS
    
    from threading import Thread
    from wx.lib.pubsub import Publisher
    
    ########################################################################
    class FtpValues(object):
        """ Returns a property attribute - called by FtpFileTransfer
        Used to set values/variables for Host, USERID, PASSWD, FILE """
    
        #----------------------------------------------------------------------
        def __init__(self):
            self.varList = None
    
        #----------------------------------------------------------------------    
        def GetValues(self):
            return self.varList
    
        #----------------------------------------------------------------------
        def SetValues(self, HOST, USERID, PASSWD, FILE):
            self.varList = [HOST, USERID, PASSWD, FILE]
    
        #----------------------------------------------------------------------
        def DelValues(self):
            del self.valList
    
        Values = property(GetValues, SetValues, DelValues, "Set/Get FtpValues")
    
        # http://docs.python.org/library/functions.html#property
    
    ########################################################################
    class FtpFileTransfer(Thread):
        """Test Worker Thread Class."""
    
        #----------------------------------------------------------------------
        def __init__(self):
            """Init Worker Thread Class."""
            Thread.__init__(self)
            self.StartTransfer()        # start the thread
    
        #----------------------------------------------------------------------
        def StartTransfer(self):        # was named run - started automatically                                    
            """Run Worker Thread."""    # when called by the start method
            # This is the code executing in the new thread.
    
            HOST, USERID, PASSWD, FILE = FtpValues.Values
            BLOCKSIZE = 57344
            try:
                ftp = FTP_TLS(HOST)
                ftp.login(USERID, PASSWD)
                ftp.prot_p()
                ftp.voidcmd("TYPE I")
                f = open(FILE, 'rb')
                datasock, esize = ftp.ntransfercmd(
                        'STOR %s' % os.path.basename(FILE))
                size = os.stat(FILE)[6]
                bytes_so_far = 0
                while 1:
                    buf = f.read(BLOCKSIZE)
                    if not buf:
                        break
                    datasock.sendall(buf)
                    bytes_so_far += len(buf)
                    msg = [bytes_so_far, size]
                    Publisher().sendMessage("update", msg)
            except: raise
            finally:
                try:
                    datasock.close()
                    f.close()
                    ftp.voidresp()
                    ftp.quit()
                    print 'Complete...'
                except: pass
    
            wx.CallAfter(Publisher().sendMessage, "update", "Database Transfer Complete!")
    
    
    ########################################################################
    class ProgressDialog(wx.Dialog):
    
        def __init__(self, parent, title):
            super(ProgressDialog, self).__init__(parent=parent, 
                title=title, size=(500, 110))
    
            self.displayLbl = wx.StaticText(self, -1, 'Verifying Database Files... ', (20, 20)) #Preparing for Transfer...
            self.gauge = wx.Gauge(self, -1, 100, (20, 45), (370, 24))        
            self.btn = btn = wx.Button(self, -1, 'Cancel', (400, 45), (-1, 25))
            btn.Bind(wx.EVT_BUTTON, self.OnClose)
    
            # listens for response from worker thread
            Publisher().subscribe(self.updateDisplay, "update")
    
            FtpFileTransfer()#.StartTransfer(HOST, USERID, PASSWD, FILE)        #Start the FTP Worker Thread
            #self.OnStart()
    
        #----------------------------------------------------------------------
        def run(self):
            FtpFileTransfer(HOST, USERID, PASSWD, FILE)
    
        #----------------------------------------------------------------------
        def OnClose(self, event):
            """ Place Holder """
            if self.btn.GetLabel() == 'Finish':
                # Do Something!
                pass
            return None
    
        #----------------------------------------------------------------------
        def updateDisplay(self, msg):
            """ Receives data from thread and updates the display """
            if isinstance(msg.data, list):
                bytes_so_far, size = msg.data
                k = 100 * bytes_so_far / size
                self.displayLbl.SetLabel("Sent %d of %d bytes %.1f%%" % (bytes_so_far, size, 100 * bytes_so_far / size))
                self.gauge.SetValue(k)
            else:
                self.displayLbl.SetLabel("%s" % msg.data)
                #self.btn.Enable()
                self.btn.SetLabel('Finish')
    
    
    ########################################################################
    class MyForm(wx.Frame):
    
        #----------------------------------------------------------------------
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
    
            # Add a panel so it looks the correct on all platforms
            panel = wx.Panel(self, wx.ID_ANY)
            self.displayLbl = wx.StaticText(panel, label="Amount of time since thread started goes here")
            self.btn = btn = wx.Button(panel, label="Start Thread")
            self.gauge = wx.Gauge(panel, -1, 100, size=(370, 24))
    
            btn.Bind(wx.EVT_BUTTON, self.onButton)
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.displayLbl, 0, wx.ALL|wx.CENTER, 5)
            sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
            sizer.Add(self.gauge, 0, wx.ALL|wx.CENTER, 5)
            panel.SetSizer(sizer)
    
            self.VarData()
            # create a pubsub receiver
            Publisher().subscribe(self.updateDisplay, "update")
    
        #----------------------------------------------------------------------
        def onButton(self, event):
            """
            Runs the thread
            """
    
            chgdep = ProgressDialog(None, title='File Transfer. . .')
            chgdep.ShowModal()
            #chgdep.Destroy()
    
        #----------------------------------------------------------------------
        def updateDisplay(self, msg):
            """
            Receives data from thread and updates the display
            """
            if isinstance(msg.data, list):
                bytes_so_far, size = msg.data
                k = 100 * bytes_so_far / size
                self.displayLbl.SetLabel("Sent %d of %d bytes %.1f%%" % (bytes_so_far, size, 100 * bytes_so_far / size))
                self.gauge.SetValue(k)
            else:
                self.displayLbl.SetLabel("%s" % msg.data)
                self.btn.Enable()
    
        #----------------------------------------------------------------------
        def VarData(self):
            HOST = '127.0.0.1'
            USERID = 'test'
            PASSWD = 'P@ssw0rd'
            FILE = r'F:\Programming\temp\Test.zip'
            varList = [HOST, USERID, PASSWD, FILE]
            FtpValues.Values = HOST, USERID, PASSWD, FILE
    
    #----------------------------------------------------------------------
    # Run the program
    if __name__ == "__main__":
        app = wx.PySimpleApp()
        frame = MyForm().Show()
        app.MainLoop()
    

5 个答案:

答案 0 :(得分:2)

就个人而言,我喜欢使用wx.lib.pubsub在类之间传递信息。我在我的应用程序中一直这样做。您可以在此处阅读:http://www.blog.pythonlibrary.org/2010/06/27/wxpython-and-pubsub-a-simple-tutorial/

如果需要从线程发布数据,则需要使用线程安全的方法,如wx.CallAfter,wx.CallLater或wx.PostEvent。您可以通过在其中一个线程安全方法中调用pubsub发布者来将这些与pubsub结合使用。我在这里展示了如何做到这一点:http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

在他们的wiki上还有关于线程和wxPython的好文章:http://wiki.wxpython.org/LongRunningTasks

答案 1 :(得分:1)

问题中提出的方法是Python中首选的方法。 b.do_something(f.var)__init__(self, parent, title, myVar)等语句是非常好在类之间传递信息的方法。

这种情况在开始时很常见,但我的猜测是你在某个地方犯了一个小的语法错误,并且认为这意味着你采取了错误的一般方法。相反,您的一般方法看起来很好,但您只需要找出导致特定错误的原因。

对其他答案的评论:

1)Set / get函数也运行良好,但Python更喜欢properties方法。 (就个人而言,我仍然习惯使用set / get方法,但它不像Pythonic。)

2)pubsub很棒,但它不是“在类之间传递信息”的通用工具,例如,人们不希望将pubsub用于i = int(“2”)。 Pubsub更适用于例如两个wxFrame需要传达一些信息的情况。有一个原因,它是wxPython的一部分,而不是Python。

答案 2 :(得分:0)

在OOP中,如果要将数据传入和传出对象,则应在该类中定义set / get函数,以便可以从该对象获取数据以及在该对象中设置数据。因此,在您的情况下,对象的每个实例都会调用相应的get / set函数来在对象之间来回传递数据。

答案 3 :(得分:0)

你可能已经在几个月前完成了工作,但我刚刚遇到了一个wxPython对话框的问题,并通过在函数中使用通知全局来使其工作:

elusive_variable="" # declare outside class & function

class MyForm(wx.Frame):

    def onOpenFile(self, event):
        global elusive_variable
        # ...other stuff here
        elusive_variable="Oh hi Mark"

if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
print elusive_variable # variable is liberated!!!

可能会有一些更有启发性的方式,但这有效......

答案 4 :(得分:0)

以下是一个例子:

class One:
    param1 = ['a', 'b']

class Two:
    i = One()
    print i.param1

将以上代码保存在.py文件中并运行它。你应该看到输出 我想这可以是将变量从一个类交换到另一个类的简单方法

相关问题