python3中eval函式用法簡介
python中eval函式的用法十分的靈活,這裡主要介紹一下它的原理和一些使用的場合。
下面是從python的官方文件中的解釋:
The arguments are a string and optional globals and locals. If provided, globals must be a dictionary. If provided, locals can be any mapping object.
The expression argument is parsed and evaluated as a Python expression (technically speaking, a condition list) using the globals
builtins
module and restricted environments are propagated. If the
localseval()
is called. The return value is the result of the evaluated expression. Syntax errors are reported as exceptions. Example:
>>> x = 1 >>>eval('x+1') 2
This function can also be used to execute arbitrary code objects (such as those created by
compile()
). In this case pass a code object instead of a string. If the code object has been compiled with
'exec'
as the mode argument,
eval()
‘s return value will be
None
.
Hints: dynamic execution of statements is supported by the
exec()
function. The
globals()
and
locals()
functions returns the current global and local dictionary, respectively, which may be useful to pass around for use by
eval()
or
exec()
.
See
ast.literal_eval()
for a function that can safely evaluate strings with expressions containing only literals.
下面我做一下簡單的翻譯,有可能有一些翻譯不好的地方,見諒。
函式原型:
eval
(expression,
globals=None, locals=None)
引數:
expression:這個引數是一個字串,python會使用globals字典和locals字典作為全域性和區域性的名稱空間,將expression當做一個python表示式(從技術上講,是一個條件列表)進行解析和計算。
globals:這個引數管控的是一個全域性的名稱空間,也就是我們在計算表示式的時候可以使用全域性的名稱空間中的函式,如果這個引數被提供了,並且沒有提供自定義的__builtins__,那麼會將當前環境中的__builtins__拷貝到自己提供的globals裡,然後才會進行計算。關於__builtins__,它是python的內建模組,也就是python自帶的模組,不需要我們import就可以使用的,例如我們平時使用的int、str、abs等都在這個模組中。關於它的說明可以參照這篇文章:點選開啟連結。如果globals沒有被提供,則使用python的全域性名稱空間。
locals:這個引數管控的是一個區域性的名稱空間,和globals類似,不過當它和globals中有重複的部分時,locals裡的定義會覆蓋掉globals中的,也就是當globals和locals中有衝突的部分時,locals說了算,它有決定權,以它的為準。如果locals沒有被 提供的話,則預設為globals。
eval函式也可以被用來執行任意的程式碼物件(如那些由compile()建立的物件)。在這種情況下,expression引數是一個程式碼物件而不是一個字串。如果程式碼物件已經被‘exec‘編譯為模式引數,eavl()的返回值是None。
下面舉一些例子進行講解:
三個引數的使用:
1、在前兩個引數省略的情況下,eval在當前的作用域執行:
a=10;
print(eval("a+1"))
執行結果為:11
在這種情況下,後兩個引數省略了,所以eval中的a是前面的10。對於eval,它會將第一個expression字串引數的引號去掉,然後對引號中的式子進行解析和計算。
2、在globals指定的情況下:
a=10;
g={'a':4}
print(eval("a+1",g))
執行結果為:5
這裡面可能有點繞啊,初學者得理理清楚。在這次的程式碼中,我們在 eval中提供了globals引數,這時候eval的作用域就是g指定的這個字典了,也就是外面的a=10被遮蔽掉了,eval是看不見的,所以使用了a為4的值。
3、在 locals指定的情況下 :
a=10
b=20
c=30
g={'a':6,'b':8}
t={'b':100,'c':10}
print(eval('a+b+c',g,t))
執行的結果為:116
這裡面就更有點繞人了,此次執行的結果中,a是6,b是100,c是10。我們首先來看一下,對於a為6我們是沒有疑問的,因為在上個例子中已經說了,g會遮蔽程式中的全域性變數的,而這裡最主要的是為什麼b是100呢?還記得我們在引數介紹的時候說過,當locals和globals起衝突時,locals是起決定作用的,這在很多程式語言裡都是一樣的,是作用域的覆蓋問題,當前指定的小的作用域會覆蓋以前大的作用域,這可以理解為一張小的紙蓋在了一張大的紙上,紙是透明的,上面寫的東西是不透明的,而它們重合的地方就可以理解成兩個作用域衝突的地方,自然是小的顯現出來了。
使用的場合
對於eval的使用,我們一定要確保第一個引數expression滿足表示式的要求,它是可以被解析然後計算的。
s="abck"
print(eval(s))
執行的結果為:NameError: name 'abck' is not defined
對於當面的程式碼,我們可以看到,字串s並不滿足表示式的要求。當eval剝去了"abck"的外面的引號的時候,它會對它進行解析,然後滿足要求後進行計算,然後它解析到的是abcd,請注意,程式報出的錯誤是NameError,也就是說,當它解析到這個表示式是不可以計算後,它就會查詢它是不是一個變數的名字,如果是一個變數的名字,那麼它會輸出這個變數的內容,否則就會產生這種報錯。
s="abck"
print(eval('s'))
執行的結果為:abck
對於這個程式碼,我們就可以看出來了,eval首先將‘s’的引號剝去,然後得到的是s,顯然這個是不可以進行計算的,那麼它就開始查詢s是否是一個變數的名字,然後它一查詢,果然s是一個字串,所以程式輸出了s中的內容。
在上面一直說到expression的要求,那麼它到底是什麼具體要求呢?下面仍然通過例子進行說明。
s='"sas"'
print(eval(s))
執行的結果為:sas
對於這個程式碼,我們繼續分析,eval首先去除單引號,eval在執行的時候是隻會去除同種型別的引號的,對於單引號和雙引號它是加以區分的。eval去除單引號後得到了“sas”,這個時候程式解析到它是一個字串,不可以計算,就輸出了它。那麼不禁想問,為什麼上個例子中s="abck"會不行呢,這裡面我們就可以看出區別了,一個是有引號括起來的,一個是沒有的,引號括起來代表字串,雖然不可以求值,但是是有意義的,可以進行輸出,而沒引號的便無法判斷“身份”了,只能當做變數名進行解析,而abck並不是一個變數名,所以就報錯了。
s='["a","b","c"]'
print(eval(s))
執行的結果為:['a', 'b', 'c']
對於這個程式就不多做解釋了,eval去除引號後會檢查到它是不可計算的,但它是一個列表,便輸出了裡面的內容。
a=10
b=20
c=30
s='[a,b,c]'
print(eval(s))
執行的結果為:[10, 20, 30]
對於這個程式的結果,是不是有點意外,這裡需要說明的是,eval檢查到列表的‘[’‘]’符號時,是會對裡面的元素進行解析的,這裡a、b、c顯然不是具體的資料,便去查詢它們是否是變數名,然後確認是變數名後,用它們的內容替換掉它。
s='abs(10)'
print(eval(s))
執行的結果為:10
對於這個程式,我們舉的是一個滿足計算的一個表示式,當eval剝去s的引號後,得到abs(10),然後它會對進行解析,這個解析我們前面介紹eval的時候說過,它會使用globals的內建模組__builtins__進行解析的,在這個內建模組中是有abs這個函式的,所以對abs(10)進行了計算。
關於__builtins__模組中有哪些東西 ,我們可以這樣檢視:
print(dir(__builtins__))
執行結果為:
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
在這裡我們可以看見這個模組中所有的東西,eval在進行計算的時候也是在這裡進行查詢的
到這裡,eval的解釋說明就結束了。