日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

利用抽象语法树检查Python中“未定义”的变量名

發布時間:2025/7/25 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用抽象语法树检查Python中“未定义”的变量名 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

其實,Python是一種真正的動態語言,代碼中的變量名本沒有“聲明”或“定義”的說法,語言本身也沒有提供聲明或定義變量的特殊語法(global除外)。對程序員來說,這是一種好處,也是一種危險,比如像下面這段代碼:

count = total = 1
delta = 0.7
while total < 1000:
? total += delta * (count * count + delta * delta)
? dalta = delta * 1.1
? count *= dalta
print total

代碼后面的dalta是delta拼寫錯誤的結果,程序可以正確運行,也可以通過pychecker工具的檢查,但其輸出顯然與預期的正確結果相差甚遠。不少人認為像Perl中的strict或Visual Basic中的Option Explicit可以幫助程序員減少出現類似錯誤的幾率(盡管我自己并不這么想),但在Python中,因為沒有顯式定義或聲明變量名的語法,這種強制檢查似乎較難下手——網上可以查到一些解決方案,但或者比較復雜,或者是用__slots__,decorator這樣的機制來解決部分問題,用起來不太方便。

也許,利用parser或compiler包提供的抽象語法樹(Abstract Syntax Tree)可以比較簡單地解決這個問題。我大致寫了一段名為strict.py的代碼。為了將自己的程序改為強制聲明變量的“安全代碼”,我們只需要按照strict.py的要求,用 __decl__ = "name1 name2 ..." 這樣簡單的語法在使用前預先聲明變量名即可。例如,可以在上面那段危險代碼的開頭加上:

__decl__ = "delta total count"

然后用strict.py檢查這段代碼(假設其文件名為test.py):

python strict.py test.py

我們可以在運行結果中看到:

File 'test.py', line 6: name 'dalta' is not declared.

瞧,很容易就把拼寫錯誤的變量名 dalta 給找出來了——因為 dalta 這個名字沒有預先“聲明”。

strict.py也可以檢查Class或Function等代碼塊內部的局部名字( __decl__ = "..." 這樣的聲明語句可以用在代碼中的任何位置),可以識別from ... import、global或函數參數表等引入的名字。像下面這樣的代碼:

__decl__ = 'name1 name2 name3'

name1 = 1
name2 = 'Jack'
name3 = name1 + 3

def foo():
? global name1
? __decl__ = 'local_name1 local_name2'
? name1 += 4
? local_name1 = 1.2
? local_name2 = 'Mike'
? undeclared = 9

strict.py可以很快找出其中的undeclared是“未聲明”的名字。

strict.py只檢查那些作為賦值目標的名字(l-value),對于讀取某個名字,調用某個函數名,通過 obj.attr 這樣的語法訪問對象的屬性或成員等等情況,strict.py沒有必要考慮——因為如果這些情況中出現了未定義的名稱,編譯或運行程序時就會報出錯誤來,不會造成潛在的危險隱患。

因為只是示例性質的代碼,我只在Python 2.4.3的環境下測試過strict.py,也沒有做更多復雜的測試。這段代碼一定還有許多需要改進之處。先把strict.py的代碼羅列在下面吧:


strict.py
------------------------------------------------------

import sys
import compiler

declaration_flag = "__decl__"

def find_undeclared_names(ast, frames, is_decl):

??? next_frames = frames

??? def add_name(name):
??????? frames[-1][name] = True

??? def find_name(name):
??????? return frames[-1].has_key(name)

??? def get_alias(name_pair):
??????? if name_pair[1] is None:
??????????? return name_pair[0]
??????? else:
??????????? return name_pair[1]

??? if ast.__class__.__name__ == "AssName":
??????? if not is_decl[0] and ast.name == declaration_flag:
??????????? is_decl[0] = True
??????? elif not find_name(ast.name):
??????????? yield ast.name, ast.lineno

??? elif ast.__class__.__name__ == "Global":
??????? map(add_name, ast.names)

??? elif ast.__class__.__name__ == "From":
??????? if (ast.names[0][0] == "*"):
??????????? mod = __import__(ast.modname)
??????????? map(add_name, filter(lambda x:not x.startswith('_'), dir(mod)))
??????? else:
??????????? map(add_name, map(get_alias, ast.names))

??? elif ast.__class__.__name__ == "Const":
??????? if is_decl[0] and ast.value.__class__.__name__ == "str":
??????????? map(add_name, ast.value.split())
??????????? is_decl[0] = False

??? elif ast.__class__.__name__ == "Function":
??????? next_frames = frames + [dict(map(lambda x: (x, True), ast.argnames))]

??? elif ast.__class__.__name__ == "Class":
??????? next_frames = frames + [{}]

??? for childNode in ast.getChildNodes():
??????? for x in find_undeclared_names(childNode, next_frames, is_decl):
??????????? yield x

if __name__ == "__main__":
??? if len(sys.argv) != 2:
??????? print "Usage: python strict.py <python-source-file>"
??? else:
??????? for name, line_no in /
??????????????? find_undeclared_names(compiler.parseFile(sys.argv[1]),
????????????????????????????????????? [{}],
????????????????????????????????????? [False]):
??????????? print "File '%s', line %d: name '%s' is not declared." % /
????????????????? (sys.argv[1], line_no, name)

轉載于:https://www.cnblogs.com/xiaomaohai/archive/2006/05/14/6157194.html

總結

以上是生活随笔為你收集整理的利用抽象语法树检查Python中“未定义”的变量名的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。