2016-04-09 24 views
3

我是Python新手,對於在循環中聲明的變量範圍感到困惑。我看過一些例子,但在我的具體情況下,我很難理解它。循環中的Python變量範圍示例

例如,我看到了下面的代碼段here

with ZipFile(self.archive_name, "r") as archive: 
    for id, files in data.items(): 
     if files: 
      print("Creating", id) 
      dirpath = os.path.join(directory, id) 

      os.mkdir(dirpath) 

      for file in files: 
       match = pattern.match(filename) 
       new = match.group(2) 
       new_filename = os.path.join(dirpath, new) 

       content = archive.open(file).read() 
      with open(new_filename, "wb") as outfile: 
       outfile.write(content) 

我基本上上面的代碼中非常方式相同,但與循環內執行不同的語句重複這些類似的代碼片段在我的__main__中一個接一個。我的問題是:在重複的代碼需要給新的名字給變量archiveidfilefilesoutfile與否?會有衝突或什麼?要記住有什麼好的做法?

+0

修改我的問題,添加關於這些類似的代碼段位於何處的信息。 –

回答

3

假設這段代碼在函數中,那麼變量的作用域就是函數的結尾。如果這段代碼在模塊級別,那麼變量的範圍就是模塊(又名全局)範圍。

你不要使用不同的名稱。下面的代碼只會在不同的時間分配給archive變量不同的對象:

with ZipFile(self.archive_name, "r") as archive: 
    print(id(archive)) 

with ZipFile(self.archive_name, "r") as archive: 
    print(id(archive)) 

這是相同的:

archive = ZipFile(self.archive_name, "r") 
with archive: 
    print(id(archive)) 
archive = ZipFile(self.archive_name, "r") 
with archive: 
    print(id(archive)) 

也就是說,與with報表相關和循環唐塊」就變量而言,定義一個範圍,它們是「正義」的任務。您應該看到爲不同對象的ID打印了兩個不同的值。

請注意,由於您的示例代碼使用id作爲變量名,因此我應該小心使用使用內置函數id的示例!

有沒有什麼好的實踐方面的問題需要牢記?

在誤入自以爲是領土的風險:

  • 你很少使用外循環的循環變量的值。因此,通常通常是,可以在函數後面的新循環中再次使用相同的循環變量,但一般而言,在再次使用該函數之前,應該先檢查該變量名稱的所有所有。對於模塊級代碼來說,這更糟糕:在添加第二個循環之前,需要確保模塊的外部用戶不依賴於具有第一個循環留下的值的變量。
  • 除非對象在兩個不同的地方提供相同的角色確切的,然而儘管在函數後面重用變量是安全的,但它仍然有點令人困惑。
  • 很明顯,在將代碼複製粘貼到函數兩次之前,要合理確信在特定情況下,重複(大概會進行一些更改)確實比定義另一個函數並將其調用兩次要好。
+0

謝謝你的回答。只需要澄清;你說'如果這段代碼在模塊級別,那麼變量的範圍就是我的代碼所在的模塊(又名全局)範圍。所以,'不必使用不同的名字'。這讓我困惑。我的意思是,因爲它是全局作用域,首次聲明時的'id'變量,它會不會'持有'它的值直到結束?對不起,如果我在理解這個方面速度很慢:) –

+1

@ hask.duke:如果這個代碼在模塊級別,那麼'id'變量將保存你給它的值直到文件結束,或者直到你指定了一個新的價值(這是你的第二個循環會做什麼)。此外,導入模塊的其他模塊將能夠以'your_module_name.id'的形式訪問其最終值。這是避免在模塊級編寫大量代碼的一個原因。它並不能真正幫助任何人在自動生成的文檔中看到循環變量,在調試器使用模塊時調用'dir()'等等。 –

+0

因此,如果我正確地理解了這一點,那麼出現在第二個代碼段上的'id'變量沒有問題,主要是因爲它被重新初始化了?也就是說,如果在第一個代碼段結束後立即調用了id而沒有初始化該代碼段,那麼它將保存在第一個代碼段的第一個循環結束時得到的任何值。 –

3

通常,縮進塊不會啓動新的作用域。只有模塊,類和函數定義新的作用域。 (在Python 3中,list/set/dict理解中的索引是理解本地的。)

在你的例子中,例如,archive在整個模塊/類/函數的範圍內其中發生了with聲明,就像首先分配給with聲明正文內的任何變量一樣。如果with語句位於模塊範圍內,則所有分配均爲模塊全局。如果它位於類定義的頂層,則它們都是類屬性。如果它(可能)在函數或方法聲明中定義,那麼它們對於該函數是本地的。