我想检查一个函数对象,以了解函数是否正在访问任何双下划线属性(例如'__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__')
但是如果函数连接'_',或者更糟糕的是,使用字符或unicodes,那么似乎没有一种明显的方法可以在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', '_')
那么,有什么方法可以确保在函数中捕获所有双下划线访问权限吗?
答案 0 :(得分:0)
您始终可以在代码上运行pylint
。
正如所指出的那样,有一些方法可以检查它,但是另一种选择,或者可能是一起,在代码开头附近添加一些东西:
oldgetattr = getattr
def getattr(x,y):
""" No __ access__ """
assert not y.startswith('__')
return oldgetattr(x,y)
然后运行代码 - 您可能还需要以类似的方式编写补丁object.__getattribute__
。
以上是在python 2.7.5+上测试的,似乎可以完成这项工作
>>> def foo(): import math; print(getattr(math, chr(95)*2 + 'doc' + '_' + chr(95)))
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in foo
File "<stdin>", line 3, in getattr
AssertionError
>>>
答案 1 :(得分:0)
Python 3提供了__getattribute__
方法,可以完全控制对类实例的访问。这不会解决内置类型,但它会让您检测自己(传入)对象的访问。
此外,您可以使用CodeObject将全局变量字典替换为您自己的字典。因此,您可以使用getattribute方法扩展字典,并将其作为全局命名空间插入。这应该让您可以看到全局访问。然后替换global getattr?
看看你走了多远。