2017-06-13 67 views
1

通常在C程序(和使用GCC)中,我將創建一個調試打印宏,其中包含當前函數的名稱。也就是說,這樣的:在Python中打印時包含當前方法名稱

#define DPRINTF(fmt, ...) printf("[%s] " fmt, __FUNCTION__, ##__VA_ARGS__) 

使用時,當前的功能將被預置到每個打印,提供在運行時更加有用的調試信息。例如,下面的代碼

#include <stdio.h> 

#define DPRINT(fmt, ...) printf("[%s] " fmt, __FUNCTION__, ##__VA_ARGS__) 

void testfunction1(){ 
    DPRINT("Running %d\n",1); 
} 

void testfunction2(){ 
    DPRINT("Running %d\n",2); 
} 

int main(void) { 
    DPRINT("Running: %d\n",0); 
    testfunction1(); 
    testfunction2(); 
    return 0; 
} 

將輸出:

[main] Running: 0 
[testfunction1] Running 1 
[testfunction2] Running 2 

能像這樣在Python做呢?

我搜索了一下,發現this StackOverflow問題,解釋如何使用inspect從堆棧中讀取名稱。但是,從我發現的Python不支持宏,所以不能使用與我的C程序相同的窗體。

是否有某種機制可以支持這種類型的調試打印?我嘗試了lambda表達式,但本例中的「函數名稱」打印爲「< lambda>」。

+0

它仍然不清楚什麼你期待 –

+0

@AmeyYadav ,更新了問題。 – sherrellbc

+0

你可以把你嘗試過的示例代碼放在哪裏,通常很容易從那裏開始。爲了快速回答,是的,你可以在python中檢查裝飾器的使用。你可以包裝一個函數來調試它的名字。 – suvy

回答

1
import inspect 
import sys 
def DPRINT(fmt, *args): 
    print "{} {} {}".format(sys._getframe(1).f_code.co_name, fmt, args) 

    # below line is another way to get the name of a calling function 
    # print "{} {} {}".format(inspect.stack()[1][3], fmt, args) 

def testfunction1(): 
    DPRINT("Running: 1") 

def testfunction2(): 
    DPRINT("Running: 2") 

def main(): 
    DPRINT("Running: 0") 
    testfunction1() 
    testfunction2() 

main() 

我不知道這可能是有益的

+0

哦..男人。當我正在閱讀你的解決方案時,它非常明顯。如果您可以從堆棧中讀取當前函數的名稱,那麼您也可以從堆棧中讀取調用者的名字。 – sherrellbc

+0

確實如此@sherrellbc –

+1

@AmeyYadav - 讀取整個堆棧以抓取最後一幀非常浪費,tho。 – zwer

3

您可以檢查的最後一幀檢索呼叫者姓名和剩下的就是簡單的格式,像

import sys 

def dprint(fmt=None, *args, **kwargs): 
    try: 
     name = sys._getframe(1).f_code.co_name 
    except (IndexError, TypeError, AttributeError): # something went wrong 
     name = "<unknown>" 
    print("[{}] {}".format(name, (fmt or "{}").format(*args, **kwargs))) 

def testfunction1(): 
    dprint("Running {}", 1) 

def testfunction2(): 
    dprint("Running {}", 2) 

def main(): 
    dprint("Running {}", 0) 
    testfunction1() 
    testfunction2() 
    return 0 

if __name__ == "__main__": 
    main() 

# prints: 
# [main] Running 0 
# [testfunction1] Running 1 
# [testfunction2] Running 2 
2

我會建議根本不使用print,而是建立一個logger。記錄模塊具有適用於所有LogRecordfuncName屬性。

你再有(從zwer的回答採取代碼):

import logging 

def create_logger(app_name=None): 
    logger = logging.getLogger(app_name or __name__) 
    logger.setLevel(logging.DEBUG) 
    log_format = '[%(asctime)-15s] [%(levelname)08s] (%(funcName)s %(message)s' 
    logging.basicConfig(format=log_format) 
    return logger 

LOGGER = create_logger() 

def testfunction1(): 
    LOGGER.info("Running %d", 1) 

def testfunction2(): 
    LOGGER.error("Running %s", 2) 

def main(): 
    LOGGER.debug("Running %03d", 0) 
    testfunction1() 
    testfunction2() 

if __name__ == "__main__": 
    main() 

這將產生類似於:

[2017-06-13 19:41:45,677] [ DEBUG] (main) Running 000 
[2017-06-13 19:41:45,677] [ INFO] (testfunction1) Running 1 
[2017-06-13 19:41:45,677] [ ERROR] (testfunction2) Running 2 
+0

更健壯的答案 –