簡體   English   中英

如何在Python中訪問當前執行的模塊或類名?

[英]How can I access the current executing module or class name in Python?

我希望能夠從導入的模塊中動態檢索當前執行的模塊或類名。 這是一些代碼:

foo.py:

def f():
    print __name__

bar.py:

from foo import f

def b(): f()

這顯然不起作用,因為__name__是包含該函數的模塊的名稱。 我想在foo模塊中訪問的是使用foo的當前執行模塊的名稱。 所以在上面的情況下它會是bar但是如果任何其他模塊導入foo我希望foo動態地訪問該模塊的名稱。

編輯: inspect模塊看起來非常有前景,但它並不完全是我想要的。 我希望的是我可以訪問的某種全局或環境級變量,它包含當前執行模塊的名稱。 並不是說我不願意遍歷堆棧來查找信息 - 我只是認為Python可能已經暴露了這些數據。

編輯:這是我試圖使用它的方式。 我有兩個不同的Django應用程序,它們都需要將錯誤記錄到文件中。 讓我們說它們被稱為“AppOne”和“AppTwo”。 我還有一個地方可以記錄這些文件:“ /home/hare/app_logs ”。 在任何給定點的每個應用程序中,我希望能夠導入我的記錄器模塊並調用將日志字符串寫入文件的日志功能。 但是,我想要做的是在app_logs下創建一個目錄,該目錄是當前應用程序的名稱(“AppOne”或“AppTwo”),以便每個應用程序的日志文件都將放在各自的日志記錄目錄中。

為了做到這一點,我認為最好的方法是記錄器模塊可以訪問某種表示當前應用程序名稱的全局變量,因為它負責了解父日志記錄目錄的位置並創建應用程序的日志記錄目錄,如果它還不存在。

從評論 - 不是問題。

我很想知道我想做的事情是否可行。

“有可能”的答案總是“是”。 總是。 除非您的問題涉及時間旅行,反重力或永久運動。

由於答案總是“是”,你的問題是不正確的。 真正的問題是“讓我的日志記錄模塊知道客戶端名稱的好方法是什么?” 或類似的東西。

答案是“接受它作為參數”。 不要亂用於檢查或尋找神秘的全局或其他技巧。

只需遵循logging.getLogger()的設計模式,並使用顯式命名的記錄器。 一個常見的習語如下

logger= logging.getLogger( __name__ )

它幾乎可以完美地處理所有日志命名。

這應該適用於引用當前模塊:

import sys
sys.modules[__name__]

“當前正在執行的模塊”顯然是foo,因為它包含當前正在運行的功能 - 我認為更好的描述你想要的是foo的直接調用者的模塊(如果你調用af(這可能本身就是foo)從一個函數調用foo函數調用吧。你想要達到多遠取決於你想要的東西。

在任何情況下,假設您想要直接調用者,您可以通過向上調用堆棧來獲得此調用。 這可以通過調用sys._getframe來完成,並使用適當數量的級別來遍歷。

def f():
    caller = sys._getframe(1)  # Obtain calling frame
    print "Called from module", caller.f_globals['__name__']

[編輯] :實際上,如上所述使用檢查模塊可能是獲得堆棧幀的更簡潔方法。 等效代碼是:

def f():
    caller = inspect.currentframe().f_back
    print "Called from module", caller.f_globals['__name__']

(sys._getframe記錄為供內部使用 - inspect模塊是更可靠的API)

__file__是進行調用的當前模塊的路徑。

我想你想要使用的是inspect模塊,來檢查python運行時堆棧。 看看這個教程 我認為它提供了你想要做的幾乎完全的例子。

在另一個模塊中獲取對“__main__”模塊的引用:

import sys
sys.modules['__main__']

然后獲取模塊的文件路徑,其中包括其名稱:

sys.modules['__main__'].__file__

如果在“__main__”模塊中,只需使用: __file__

要從文件路徑中獲取文件名:

import os
os.path.basename(file_path)

要將文件名與其擴展名分開:

file_name.split(".")[0]

要獲取類實例的名稱:

instance.__class__.__name__

要獲取類的名稱:

class.__name__

單獨使用__file__可以為主模塊提供相對路徑,並為導入的模塊提供絕對路徑。 意識到這一點,我們可以通過os.path工具的一些幫助,無論如何都可以獲得模塊文件。

對於filename,只使用__file__.split(os.path.sep)[-1]

對於完整路徑,請使用os.path.abspath(__file__)

演示:

/tmp $ cat f.py
from pprint import pprint
import os
import sys

pprint({
    'sys.modules[__name__]': sys.modules[__name__],
    '__file__': __file__,
    '__file__.split(os.path.sep)[-1]': __file__.split(os.path.sep)[-1],
    'os.path.abspath(__file__)': os.path.abspath(__file__),
})

/tmp $ cat i.py
import f

結果:

## on *Nix ##

/tmp $ python3 f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': '/tmp/f.py'}

/tmp $ python3 i.py
{'sys.modules[__name__]': <module 'f' from '/tmp/f.pyc'>,
 '__file__': '/tmp/f.pyc',
 '__file__.split(os.path.sep)[-1]': 'f.pyc',
 'os.path.abspath(__file__)': '/tmp/f.pyc'}

## on Windows ##

PS C:\tmp> python3.exe f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

PS C:\tmp> python3.exe i.py
{'sys.modules[__name__]': <module 'f' from 'C:\\tools\\cygwin\\tmp\\f.py'>,
 '__file__': 'C:\\tools\\cygwin\\tmp\\f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

如果你想從最后剝離'.py',你可以輕松地做到這一點。 (但不要忘記你可能會運行'.pyc'。)

我不相信這是可能的,因為那是在foo的范圍之外。 foo只會知道它的內部范圍,因為它可能被無數其他模塊和應用程序調用。

自從我完成python以來已經有一段時間了,但我相信你可以通過它的回溯來訪問調用者的全局變量和本地變量。

如果您只想要文件的名稱:

file_name = __file__.split("/")[len(__file__.split("/"))-1]

要獲取包含文件夾的當前文件模塊,這對我有用:

 import os
 parts = os.path.splitext(__name__)
 module_name = parts[len(parts) - 2]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM