2015-10-15 38 views
1

在Python記錄教程進口Python記錄模塊,存在與兩個Python腳本的示例:myapp.py,和mylib.py在不同的腳本

的代碼是:

# myapp.py 
import logging 
import mylib 

def main(): 
    logging.basicConfig(filename='myapp.log', level=logging.INFO) 
    logging.info('Started') 
    mylib.do_something() 
    logging.info('Finished') 

if __name__ == '__main__': 
    main() 

# mylib.py 
import logging 

def do_something(): 
    logging.info('Doing something') 

我沒有得到的是如何使用myapp.py中的basicConfig更改中的日誌記錄行爲。

我以爲在Python中,當你用兩種不同的腳本導入相同的模塊時,它們完全斷開連接,因爲第一個模塊變成了myapp.logging,而第二個變成了mylib.logging

編輯:

我改變mylib.py代碼

# mylib.py 
import logging 


def do_something(): 
    logging.warning('Doing something') 


do_something() 

當我運行myapp.py,日誌現在打印在控制檯不會出現在日誌文件中了。這怎麼可能?

+0

是的,但您然後從另一個模塊導入一個模塊並使用其功能。 – Ffisegydd

+0

當我在mylib的末尾添加「do_something()」時,你如何解釋?py,日誌顯示在控制檯上,而不是日誌文件中? –

回答

4

有一個錯誤在你的Python的模塊理解(如果我可以調用它的):

我認爲,在Python中,當您導入在兩個不同的腳本在同一個模塊,它們是完全斷開,因爲第一個變成myapp.logging,第二個變成mylib.logging

事實並非如此。

import語句解釋時遇到它,當你在你的主程序(python myapp.py或同等)運行python,執行這些行:

import logging 

(其中進口的logging模塊),

import mylib 

(其中進口你的庫mylib.py),

def main(): 

(結合名稱main給函數的編譯字節碼),和:

if __name__ == '__main__': 
    main() 

(是運行在main因爲本地名稱__name__其實綁定到一個字符串比較等於字符串__main__)。

到目前爲止,這可能不是很令人吃驚(除可能在導入myapp.py時遇到的情況下運行)。

可能的部分令人驚訝的是執行兩個import語句期間發生的情況。

進口機械已發展了不少(並在Python3比Python2有所不同),但它在本質上確實這些不同的東西:

  • 找到該文件(使用sys.path
  • 如果這是該文件的第一進口,運行所有的可執行語句文件
  • 使用或修改sys.modules(見下文)
  • 綁定生成的對象(S)(某事<type 'module'>或其中的一個名稱)添加到您提供的名稱(隱含地使用常規import,明確使用from ... import ... as name)。

這裏的一個關鍵項目是斜體部分。該模塊實際上在第一個import上運行。成功導入的結果是一個模塊實例,其被添加到sys.modules詞典:

$ python2 
... 
>>> import sys 
>>> x = sys.modules['copy_reg'] 
>>> print x 
<module 'copy_reg' from '/usr/local/lib/python2.7/copy_reg.pyc'> 

如果在這一點上,你問蟒蛇重新導入的模塊,它會悄悄地做幾乎沒有:

>>> import copy_reg 
>>> 

這裏會發生什麼事是,Python的告示,該模塊已經加載和sys.modules因此它只是提取已加載模塊實體(一個我們也勢必以上符號x)。然後它將名稱copy_reg綁定到這個已經存在的模塊。如果您import copy_reg as y

>>> import copy_reg as y 

名字還綁定到符號y

>>> print x, y, copy_reg 
<module 'copy_reg' from '/usr/local/lib/python2.7/copy_reg.pyc'> <module 'copy_reg' from '/usr/local/lib/python2.7/copy_reg.pyc'> <module 'copy_reg' from '/usr/local/lib/python2.7/copy_reg.pyc'> 

地看到,這些其實都是相同模塊,我們可以使用id功能,打印潛在對象的內部地址:

>>> print id(x), id(y), id(copy_reg) 
34367067648 34367067648 34367067648 

(差異nt run或不同版本的Python可能會在這裏產生一組不同的3位地址值,但所有這三個地址值都會匹配,因爲這些都是指相同的模塊)。


在任何情況下,在你mainmyapp,符號logging指同一logging模塊中mylib符號logging

在你的原代碼,調用(從do_somethingmyliblogging.warningmyapp後您main打印消息已經叫日誌配置代碼。日誌消息因此按照指示進行。

在你的編輯,你已經改變mylib儘快的import mylib聲明負荷myilb無條件調用(通過do_something)的logging.warning函數來創建模塊。這發生在myapp,之前結合main到代碼和之前調用main。所以消息出來在控制檯上。

由日誌代碼決定是否服從(從後面)basicConfig來自main的呼叫。正如你可以從你自己的例子看到的那樣,它不會在打印消息之後嘗試重新定向根配置(這是因爲當時它設置了它的內部日誌處理程序,就像我記得的那樣)。

+0

謝謝!正是我在找什麼。實際上,我不知道myapp.logging和myapp.mylib.logging具有不同的名稱,但指向相同的Module對象(因爲Python會檢查模塊是否已被加載)。完美:) –

-1

根據reference記錄模塊提供了一個接口,用於創建和存儲記錄器以供將來使用,

到getLogger()具有相同名稱的多個呼叫將總是返回到相同的記錄器對象的引用。

此外,直接使用logging.info等同於獲取默認命名記錄器並使用它。您可以檢查源代碼以獲取有關此機制實現的更多詳細信息。

-1

我想你應該你的模塊

logger = logging.getLogger(__name__) 

中創建一個記錄器實例,然後使用

logger.info('message') 

登錄的東西。

編輯,根據對其他答案的評論。 設置級別不是必需的,除非你想過濾一些消息,比如只記錄下來警告。 您一定想在更改代碼後啓動新的控制檯。

1

我相信日誌級別在Python中全局工作,如果你設置它們爲logging.basicConfig

最簡單的答案可能是(as jake77 suggested already):

logger = logging.getLogger(__name__) 

然後設定的水平上記錄具體爲:

logger.setLevel(logging.DEBUG) # or whichever 

界面上有記錄here最佳實踐的好文章。它可能會或可能不會與您的情況相關,但它提供的最好建議是:

圖書館沒有業務配置日誌級別,格式化程序或處理程序。

還有一個很好的答案here

+0

我想知道爲什麼當你編寫一個文件log_config.py來寫你的日誌應該如何工作,並在其他腳本中導入log_config時,這些腳本的行爲與log_config相同。我知道我可以爲每個腳本創建一個記錄器,但那不是我的觀點。 –

+0

那麼最好的做法是在每個庫腳本中使用'logger = logging.getLogger(__ name __)',然後在主入口腳本中執行所有配置。 – Leo

+0

...這是除非你想配置多個記錄器登錄到不同的文件/控制檯,這將更加複雜。 – Leo