2013-04-05 147 views
64

我知道「.pyc」文件是在運行時創建的純文本「.py」文件的編譯版本,以使程序運行更快。但是我觀察到一些東西:什麼時候刷新.pyc文件?

  1. 修改「py」文件後,程序行爲發生變化。這表明「py」文件被編譯或者至少經過某種哈希處理或者比較時間戳以判斷它們是否應該被重新編譯。
  2. 刪除所有「.pyc」文件(rm *.pyc)後,有時程序行爲會改變。這將表明它們沒有被編譯爲「.py」的更新。

問題:

  • 他們如何決定何時進行編譯?
  • 有沒有辦法確保他們在開發過程中有更嚴格的檢查?
+10

小心刪除pyc文件與RM'* .pyc'的。這不會刪除嵌套文件夾中的.pyc文件。使用'find。 -name'* .pyc'-delete'而不是 – Zags 2014-10-07 19:53:27

+4

也許有一個關於你的問題的說明:當從'.pyc'或'.pyo'文件中讀取時,程序運行速度比從'.py'文件;關於'.pyc'或'.pyo'文件的唯一更快的速度是它們被加載的速度。 [鏈接](http://www.network-theory.co.uk/docs/pytut/CompiledPythonfiles.html) – maggie 2015-10-07 06:24:03

+0

@maggie加載和執行時間有什麼區別? – 2016-12-06 18:50:17

回答

53

.pyc只有當該python文件被某個其他腳本導入時,纔會創建(可能會覆蓋)這些文件。如果調用導入,Python會檢查文件的內部時間戳是否與相應的.py文件匹配。如果是這樣,它將加載.pyc;如果不存在或者.pyc尚不存在,Python會將.py文件編譯爲.pyc並加載它。

「嚴格檢查」是什麼意思?

+3

我可以解決'rm * .pyc'的問題。我知道,如果我強制重新創建所有文件,則會修復一些問題,表明這些文件沒有被自己重新編譯。我想如果他們確實使用時間戳,那麼就沒有辦法讓這種行爲更加嚴格,但問題仍然存在。 – 2013-04-05 17:34:13

+10

這不完全正確。時間戳不需要匹配(他們通常不會)。 '.pyc'的時間戳必須比相應的'.py'的時間戳更老,以觸發重新編譯。 – 2013-04-05 17:35:04

+0

@TimPietzcker啊,當然這是有道理的。很高興知道。而且,OP還有其他一些可以由Python導入的文件。例如'.so'是一個編譯後的C擴展,它可以被Python調用,就好像它是'.pyc'文件一樣。除此之外,我需要更多關於你的問題的細節來提供其他的東西。 – DaveTheScientist 2013-04-05 17:38:19

21

。每當導入相應的代碼元素時生成.pyc文件,並在相應的代碼文件已更新時更新。如果.pyc文件被刪除,它們將自動重新生成。但是,它們是而不是當相應的代碼文件被刪除時自動刪除。

這會在文件級重構過程中導致一些非常有趣的錯誤。首先,你最終可以推送只能在你的機器上和別人的機器上工作的代碼。如果您對已刪除的文件有懸而未決的引用,如果您沒有手動刪除相關的.pyc文件,這些文件仍可在本地工作,因爲.pyc文件可用於導入。這是因爲一個正確配置的版本控制系統只會將.py文件推送到中央存儲庫而不是.pyc文件,這意味着您的代碼可以通過「導入測試」(一切都可以導入),而且沒有問題在別人的電腦上工作。

其次,如果將軟件包轉換爲模塊,可能會出現一些非常糟糕的錯誤。將包(具有__init__.py文件的文件夾)轉換爲模塊(.py文件)時,曾經表示該包的.pyc文件仍保留。特別是,__init__.pyc仍然存在。所以,如果你有一些代碼,也沒關係的軟件包foo,然後再刪除該程序包,並創建一個文件foo.py一些功能def bar(): pass並運行:

from foo import bar 

你:

ImportError: cannot import name bar 

因爲python仍然使用foo包中的舊.pyc文件,其中沒有一個定義bar。在網絡服務器上,這可能會特別成問題,因爲.pyc文件會導致完全正常運行的代碼可能會中斷。

由於這兩個原因(可能還有其他人),您的部署代碼和測試代碼應該刪除pyc文件,如與以下行的bash的結果:

find . -name '*.pyc' -delete 

而且,隨着python 2.6,你可以用-B標誌運行python來不使用.pyc文件。有關更多詳細信息,請參見How to avoid .pyc files?

參見:How do I remove all .pyc files from a project?

+0

「當你轉換一個模塊(一個帶有__init __。py'文件的文件夾)......」。這將是一個包,而不是一個模塊。 – 2015-09-01 18:11:39

+0

@RobertDavidGrant好點;編輯 – Zags 2015-09-01 18:37:23

+2

*特別是'__init __。pyc'保留。* - 怎麼回事?作爲一個包是一個目錄刪除一個包意味着刪除目錄,因此沒有任何文件... – 2017-09-06 12:30:31