2012-01-15 80 views
1

我在將一個類實例中定義的變量傳遞給另一個類實例時遇到問題。我對使用類相對來說比較陌生,但我的理解是,通過簡單定義類實例的一部分(如下例),就可以將變量從一個實例傳遞到另一個實例。儘管過去我使用過這個模型,但我從來沒有試過用GUI框架(例如wxPython)來做這件事。使用Python將變量從一個類實例傳遞到另一個類實例?

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. 或者,有可能創建一個自定義事件處理程序來傳遞必要的數據嗎?

爲了澄清...

我使用Python和願想,我懂得編程使用類與框架,如Tkinter的和wxPython的GUI的基本面(在此使用項目)。我寫了一個主類/實例,它從用戶那裏獲取一些數據,我希望能夠傳遞存儲在self.main_instance_var中的信息並將其傳遞給第二個類/實例(在這種情況下爲進度對話框窗口

當我試圖在我的進度對話框中使用上述模型時,我得到了一個非常不明確的語法錯誤('關鍵字arg'後面的'non-keyword 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 

基本源(由REQ uest,對不起它這麼髒):

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 = '[email protected]' 
     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() 
+0

繼承和ProgressDialog所遇到的問題對於我來說似乎不同於關於在類之間傳遞變量的問題;我懷疑回答ProgressDialog問題將解決主要問題。你可以給一個最小但可運行的程序,其中ProgressDialog不起作用。 – tom10 2012-01-17 01:10:06

+0

當然...更新後! – Simpleton 2012-01-17 20:57:22

回答

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

+0

我還是新來的,但我不知道這會在這種情況下工作......我目前正在使用此方法將更新從工作線程傳遞迴ProgressDialog窗口,但我不知道這是如何在嘗試將主應用程序實例的變量傳遞給工作線程時會起作用;你能告訴我一個這樣的例子嗎? – Simpleton 2012-01-16 20:08:05

+0

我想知道這是否可能使用某種類型的自定義事件...? – Simpleton 2012-01-16 20:12:02

+0

我在回答中增加了一些建議,但是可以,您可以使用wx.PostEvent的自定義事件,我想。 – 2012-01-17 16:58:39

0

在OOP中,如果你想傳遞數據流入和流出的對象,你應該定義一組/該類別獲得的功能,這樣就可以從該對象獲取數據以及該對象中的設置數據。所以在你的情況下,你的對象的每個實例都會調用相應的get/set函數來在你的對象之間來回傳遞數據。

+0

感謝您對面向對象編程的深入瞭解。不過,我希望稍微更詳細的迴應。我想這是我的錯,儘管...沒有指定我正在使用哪種編程語言,或者包括我編寫的部分或全部代碼。爲了將來的參考,我正在使用Python v2.7,並且將會更新我的帖子以包含更多的細節(包括源代碼)。再次感謝您的見解! – Simpleton 2012-01-16 03:13:56

1

的問題建議的方法是在Python做事的首選方式。像b.do_something(f.var)__init__(self, parent, title, myVar)這樣的語句是非常好在類之間傳遞信息的方法。

開始時很常見,但我的猜測是你在某處發現了一個小的語法錯誤,並且認爲這意味着你正在採用錯誤的一般方法。相反,你的一般方法看起來很好,但你只需要弄清楚是什麼導致了具體的錯誤。

其他解答評論:

1)設置/獲取功能的工作也很好,但是Python更喜歡properties方法。 (就我個人而言,我仍然習慣使用set/get方法,但它不像Pythonic那樣。)

2)pubsub很棒,但它不是用於「在類之間傳遞信息」的通用工具,例如,人們不希望使用pubsub作爲i = int(「2」)。 Pubsub更適用於那些需要傳遞一點信息的wxFrames的情況。有一個原因是它是wxPython的一部分,而不是Python。

+0

你說得對。然而,OP似乎在談論何時將數據從對話框或框架傳遞迴另一個框架是不同的。原始幀已經實例化,不能接受新的參數。您也可以爲任何Python項目下載PubSub – 2012-01-17 18:12:31

+0

定義屬性有很大的意義......只有這樣纔會導致對話框窗口延遲/凍結,直到工作線程完成。我是否必須實施異步編程才能使其發揮作用? [這開始變得非常複雜了!] – Simpleton 2012-01-17 20:45:14

+0

在這一點上,我認爲這太混亂了,也不清楚。最初的問題是關於在類之間傳遞變量(我認爲這是回答),但現在它似乎更多的是關於線程(這是不清楚的)。我的建議是採取每個概念,並編寫可能的最小**程序**,然後將它們測試,然後將這些想法一次添加到最終程序中。 – tom10 2012-01-17 22:28:17

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!!! 

可能更多一些enlightned的方式,但這個工程......

0

這裏有一個例子:

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

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

保存上面的代碼中.py文件並運行它。你應該看到輸出 我想這可以是一個簡單的方法來將變量從一個類交換到另一個類

相關問題