检查函数中是否使用了某些运算符

Pad*_*ham 1 python operators

我想禁止在函数中使用某些运算符,例如,我想确保**在以下函数中不使用幂运算符:

def pow(x, y):
    return x ** y
Run Code Online (Sandbox Code Playgroud)

我已经习惯inspect.getsource了获取源代码并检查是否"**"在源代码中但是如果"**"在其他地方的源代码中恰好存在断言错误,那么如何实际检查代码是否存在特定的运算符?

Jon*_*nts 9

如果你手头有3.4,我个人会去找Ashwini的答案,但是,如果你需要更多兼容并且不介意解析源代码,那么你可以利用ast,例如:

import inspect
import ast

def pow(x, y):
    return x ** y

nodes = ast.walk(ast.parse(inspect.getsource(pow)))
has_power = any(isinstance(node, ast.Pow) for node in nodes)
Run Code Online (Sandbox Code Playgroud)


Ash*_*ary 5

注意:我们在这里处理的字节代码是CPython实现细节.不要指望它可以用于其他Python实现.更喜欢Jon Clements的方法.


在CPython 3.4+中,你可以dis.get_instructions用来检查BINARY_POWER函数的代码对象中是否存在指令(在Python 3.4 doc 的新内容中也有解释):

>>> import dis
>>> def search_instruction(code_object, instr_code):
        for ins in dis.get_instructions(code_object):
            if ins.opcode == instr_code:
                return True
        return False
... 
>>> def f1():                                       
    s = x ** 2
...     
>>> def f2():
    s = 'x ** 2'
...     
>>> dis.opmap['BINARY_POWER']
19
>>> search_instruction(f1.__code__, 19)
True
>>> search_instruction(f2.__code__, 19)
False
Run Code Online (Sandbox Code Playgroud)

对于CPython 2.X,你可以尝试byteplay在PyPI上使用它的包(它的Python 3分支:https://github.com/serprex/byteplay):

>>> import byteplay
>>> def search_instruction(code_object, instr_code):
        for ins, _ in byteplay.Code.from_code(code_object).code:
                if ins == instr_code:
                    return True
        return False
...     
>>> search_instruction(f1.__code__, 19)
True
>>> search_instruction(f2.__code__, 19)
False
Run Code Online (Sandbox Code Playgroud)

相关:字节代码:什么,为什么以及如何破解它 - Ryan F Kelly博士