<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 問題 你想寫解析并分析Python源代碼的程序。 ## 解決方案 大部分程序員知道Python能夠計算或執行字符串形式的源代碼。例如: ~~~ >>> x = 42 >>> eval('2 + 3*4 + x') 56 >>> exec('for i in range(10): print(i)') 0 1 2 3 4 5 6 7 8 9 >>> ~~~ 盡管如此,`<span class="pre" style="box-sizing: border-box;">ast</span>`?模塊能被用來將Python源碼編譯成一個可被分析的抽象語法樹(AST)。例如: ~~~ >>> import ast >>> ex = ast.parse('2 + 3*4 + x', mode='eval') >>> ex <_ast.Expression object at 0x1007473d0> >>> ast.dump(ex) "Expression(body=BinOp(left=BinOp(left=Num(n=2), op=Add(), right=BinOp(left=Num(n=3), op=Mult(), right=Num(n=4))), op=Add(), right=Name(id='x', ctx=Load())))" >>> top = ast.parse('for i in range(10): print(i)', mode='exec') >>> top <_ast.Module object at 0x100747390> >>> ast.dump(top) "Module(body=[For(target=Name(id='i', ctx=Store()), iter=Call(func=Name(id='range', ctx=Load()), args=[Num(n=10)], keywords=[], starargs=None, kwargs=None), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Name(id='i', ctx=Load())], keywords=[], starargs=None, kwargs=None))], orelse=[])])" >>> ~~~ 分析源碼樹需要你自己更多的學習,它是由一系列AST節點組成的。 分析這些節點最簡單的方法就是定義一個訪問者類,實現很多?`<span class="pre" style="box-sizing: border-box;">visit_NodeName()</span>`?方法,?`<span class="pre" style="box-sizing: border-box;">NodeName()</span>`?匹配那些你感興趣的節點。下面是這樣一個類,記錄了哪些名字被加載、存儲和刪除的信息。 ~~~ import ast class CodeAnalyzer(ast.NodeVisitor): def __init__(self): self.loaded = set() self.stored = set() self.deleted = set() def visit_Name(self, node): if isinstance(node.ctx, ast.Load): self.loaded.add(node.id) elif isinstance(node.ctx, ast.Store): self.stored.add(node.id) elif isinstance(node.ctx, ast.Del): self.deleted.add(node.id) # Sample usage if __name__ == '__main__': # Some Python code code = ''' for i in range(10): print(i) del i ''' # Parse into an AST top = ast.parse(code, mode='exec') # Feed the AST to analyze name usage c = CodeAnalyzer() c.visit(top) print('Loaded:', c.loaded) print('Stored:', c.stored) print('Deleted:', c.deleted) ~~~ 如果你運行這個程序,你會得到下面這樣的輸出: ~~~ Loaded: {'i', 'range', 'print'} Stored: {'i'} Deleted: {'i'} ~~~ 最后,AST可以通過?`<span class="pre" style="box-sizing: border-box;">compile()</span>`?函數來編譯并執行。例如: ~~~ >>> exec(compile(top,'<stdin>', 'exec')) 0 1 2 3 4 5 6 7 8 9 >>> ~~~ ## 討論 當你能夠分析源代碼并從中獲取信息的時候,你就能寫很多代碼分析、優化或驗證工具了。 例如,相比盲目的傳遞一些代碼片段到類似?`<span class="pre" style="box-sizing: border-box;">exec()</span>`?函數中,你可以先將它轉換成一個AST, 然后觀察它的細節看它到底是怎樣做的。 你還可以寫一些工具來查看某個模塊的全部源碼,并且在此基礎上執行某些靜態分析。 需要注意的是,如果你知道自己在干啥,你還能夠重寫AST來表示新的代碼。 下面是一個裝飾器例子,可以通過重新解析函數體源碼、 重寫AST并重新創建函數代碼對象來將全局訪問變量降為函數體作用范圍, ~~~ # namelower.py import ast import inspect # Node visitor that lowers globally accessed names into # the function body as local variables. class NameLower(ast.NodeVisitor): def __init__(self, lowered_names): self.lowered_names = lowered_names def visit_FunctionDef(self, node): # Compile some assignments to lower the constants code = '__globals = globals()\n' code += '\n'.join("{0} = __globals['{0}']".format(name) for name in self.lowered_names) code_ast = ast.parse(code, mode='exec') # Inject new statements into the function body node.body[:0] = code_ast.body # Save the function object self.func = node # Decorator that turns global names into locals def lower_names(*namelist): def lower(func): srclines = inspect.getsource(func).splitlines() # Skip source lines prior to the @lower_names decorator for n, line in enumerate(srclines): if '@lower_names' in line: break src = '\n'.join(srclines[n+1:]) # Hack to deal with indented code if src.startswith((' ','\t')): src = 'if 1:\n' + src top = ast.parse(src, mode='exec') # Transform the AST cl = NameLower(namelist) cl.visit(top) # Execute the modified AST temp = {} exec(compile(top,'','exec'), temp, temp) # Pull out the modified code object func.__code__ = temp[func.__name__].__code__ return func return lower ~~~ 為了使用這個代碼,你可以像下面這樣寫: ~~~ INCR = 1 @lower_names('INCR') def countdown(n): while n > 0: n -= INCR ~~~ 裝飾器會將?`<span class="pre" style="box-sizing: border-box;">countdown()</span>`?函數重寫為類似下面這樣子: ~~~ def countdown(n): __globals = globals() INCR = __globals['INCR'] while n > 0: n -= INCR ~~~ 在性能測試中,它會讓函數運行快20% 現在,你是不是想為你所有的函數都加上這個裝飾器呢?或許不會。 但是,這卻是對于一些高級技術比如AST操作、源碼操作等等的一個很好的演示說明 本節受另外一個在?`<span class="pre" style="box-sizing: border-box;">ActiveState</span>`?中處理Python字節碼的章節的啟示。 使用AST是一個更加高級點的技術,并且也更簡單些。參考下面一節獲得字節碼的更多信息。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看