我想檢查一個函數對象,以知道函數是否正在訪問任何雙下劃線屬性(例如'__name__','__doc__'等)。如何檢查函數以檢查雙下劃線用法?
對於一個簡單的功能是這樣的:
In [11]: def foo(): import math; print(math.__doc__)
In [12]: foo()
This module is always available. It provides access to the
mathematical functions defined by the C standard.
我可以看看LOAD_ATTR
在反彙編輸出:
In [13]: dis.dis(foo)
1 0 LOAD_CONST 1 (0)
3 LOAD_CONST 0 (None)
6 IMPORT_NAME 0 (math)
9 STORE_FAST 0 (math)
12 LOAD_GLOBAL 1 (print)
15 LOAD_FAST 0 (math)
18 LOAD_ATTR 2 (__doc__)
21 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
24 POP_TOP
25 LOAD_CONST 0 (None)
28 RETURN_VALUE
即使功能使用簡單getattr
,我可以分析dis
輸出或看看功能代碼的co_consts
:
In [19]: def foo(): import math; print(getattr(math, '__doc__'))
In [20]: dis.dis(foo)
1 0 LOAD_CONST 1 (0)
3 LOAD_CONST 0 (None)
6 IMPORT_NAME 0 (math)
9 STORE_FAST 0 (math)
12 LOAD_GLOBAL 1 (print)
15 LOAD_GLOBAL 2 (getattr)
18 LOAD_FAST 0 (math)
21 LOAD_CONST 2 ('__doc__')
24 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
27 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
30 POP_TOP
31 LOAD_CONST 0 (None)
34 RETURN_VALUE
In [21]: foo.__code__.co_consts
Out[21]: (None, 0, '__doc__')
但是,如果函數連接'_',或者更糟糕的是,使用字符或unicode,那麼在dis
,co_consts
甚至ast
中似乎沒有明顯的方法來捕獲這些。
In [22]: def foo(): import math; print(getattr(math, chr(95)*2 + 'doc' + '_' + chr(95)))
In [23]: foo()
This module is always available. It provides access to the
mathematical functions defined by the C standard.
In [24]: dis.dis(foo)
1 0 LOAD_CONST 1 (0)
3 LOAD_CONST 0 (None)
6 IMPORT_NAME 0 (math)
9 STORE_FAST 0 (math)
12 LOAD_GLOBAL 1 (print)
15 LOAD_GLOBAL 2 (getattr)
18 LOAD_FAST 0 (math)
21 LOAD_GLOBAL 3 (chr)
24 LOAD_CONST 2 (95)
27 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
30 LOAD_CONST 3 (2)
33 BINARY_MULTIPLY
34 LOAD_CONST 4 ('doc')
37 BINARY_ADD
38 LOAD_CONST 5 ('_')
41 BINARY_ADD
42 LOAD_GLOBAL 3 (chr)
45 LOAD_CONST 2 (95)
48 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
51 BINARY_ADD
52 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
55 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
58 POP_TOP
59 LOAD_CONST 0 (None)
62 RETURN_VALUE
In [25]: foo.__code__.co_consts
Out[25]: (None, 0, 95, 2, 'doc', '_')
那麼,有什麼辦法可以肯定地捕捉函數中的所有雙下劃線訪問嗎?
我們是否假設您正在檢查的函數不接受任何參數?否則,你可以有例如'def foo(s):print(getattr(foo,s))'並調用'foo('__ doc __')',我不認爲你有任何方式來檢測它。 – senshin
我不能對這個函數做任何假設,所以這是一個公平點。我很好奇,看看別人是否有這方面的建議。 – capitalistcuttle
我懷疑你會找到任何方法來做到這一點,而不是比它的價值更麻煩。 – BrenBarn