Trong bài viết này, Quantrimang sẽ tiếp tục giới thiệu cho bạn một hàm tích hợp sẵn trong Python, đó là eval(). Eval() là một tiện ích rất thú vị cho phép bạn chạy code Python (code này được truyền dưới dạng tham số) ngay trong chương trình.
Cú pháp hàm eval() trong Python
eval(bieuthuc, global=None, local=None)
Các tham số của hàm eval():
Hàm eval() có ba tham số:
- bieuthuc: có thể là bất kì biểu thức hợp lệ nào của Python
- global: một dictionary chỉ định các phương thức và biến global có sẵn.
- local: một dictionary chỉ định các phương thức và biến local có sẵn.
Việc sử dụng global và local sẽ được Quantrimang phân tích phía sau trong bài viết này.
Giá trị trả về từ eval()
Eval() trả về kết quả được thực hiện từ bieuthuc
Ví dụ 1: Hàm eval() hoạt động thế nào?
>>> eval("5 == 5")
True
>>>
>>> eval("4 < 10")
True
>>>
>>> eval("8 + 4 - 2 * 3")
6
>>>
>>> eval("'py ' * 5")
'py py py py py '
>>>
>>> eval("10 ** 2")
100
>>>
>>> eval("'hello' + 'py'")
'hellopy'
Eval() không chỉ thực hiện được các biểu thức đơn giản mà còn có thể thực thi các hàm, gọi các phương thức, tham chiếu các biến…
>>> eval("abs(-11)")
11
>>>
>>>
>>> eval('"hello".upper()')
'HELLO'
>>>
>>>
>>> import os
>>>
>>>
>>> eval('os.getcwd()') # hiển thị thư mục đang làm việc hiện tại
'/home/thepythonguru'
>>>
>>>
>>> x = 2
>>>
>>> eval("x+4")
6
Ví dụ 2: Sử dụng eval()
# Viết bởi Quantrimang.com
# Chu vi hinh vuong
def tinhChuvi(l):
return 4*l
# Dien tich hinh vuong
def tinhDientich(l):
return l*1
thucthi = input("Nhập hàm sử dụng: ")
for l in range(1, 5):
if (thucthi == 'tinhChuvi(l)'):
print("Nếu độ dài bằng ", l , ", Chu vi = ", eval(thucthi))
elif (thucthi == 'tinhDientich(l)'):
print("Nếu độ dài bằng ", l , ", Diện tích = ", eval(thucthi))
else:
print('Hàm không chính xác!')
break
Chạy chương trình, kết quả trả về là:
Nhập hàm sử dụng: tinhDientich(l)
Nếu độ dài bằng 1 , Diện tích = 1
Nếu độ dài bằng 2 , Diện tích = 2
Nếu độ dài bằng 3 , Diện tích = 3
Nếu độ dài bằng 4 , Diện tích = 4
Nhập hàm sử dụng: tinhChuvi(l)
Nếu độ dài bằng 1 , Chu vi = 4
Nếu độ dài bằng 2 , Chu vi = 8
Nếu độ dài bằng 3 , Chu vi = 12
Nếu độ dài bằng 4 , Chu vi = 16
Nhập hàm sử dụng: tinhdientich
Hàm không chính xác!
Bạn nên cẩn thận khi sử dụng eval!
Bạn cần chú ý một chút nếu đang sử dụng một hệ thống Unix như macOS, Linux… và thực hiện các chức năng của module os. Module os được xây dựng để cung cấp các phương thức giúp bạn tạo, xóa, và thay đổi các thư mục.
Khi đó, nếu bạn cho nhập giá trị là eval(input()), người dùng có thể gặp vấn đề khi thay đổi file thậm chí xóa file bằng lệnh os.system(‘rm -rf *’).
Vì vậy, nếu bạn sử dụng eval(input()) trong code của mình, sẽ là hợp lý nếu bạn kiểm tra biến và phương thức nào mình có thể sử dụng. Bạn nên thực hiện việc này bằng hàm dir()
from math import *
print(eval('dir()'))
Chạy code và kết quả trả về sẽ có dạng như này:
['__annotations__', '__builtins__', '__doc__', '__file__', '__loader__', '__name__', '__package__',
'__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos',
'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp'
, 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma'
, 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh'
, 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
Trường hợp không truyền tham số global và local
Khi sử dụng eval() mà không truyền hai tham số này như các ví dụ phía trên, biểu thức sẽ được thực thi trong phạm vi hiện tại. Bạn có thể kiểm tra các biến và phương thức sẵn có bằng dir() như đã nói ở trên.
print(eval('dir()'))
Trường hợp truyền tham số global và bỏ qua local
Các tham số global và local (dạng dictionary) được sử dụng cho các biến toàn cục và biến cục bộ tương ứng. Nếu dictionary local bị bỏ qua, chương trình mặc định vi trí này ở dạng global. Có nghĩa là, global sẽ được sử dụng cho cả biến toàn cục và biến cục bộ.
Bạn có thể kiểm tra dictionary cục bộ và toàn cầu bằng hàm tích hợp sẵn global() và local()
Ví dụ: Truyền một dictionary trống vào tham số global
from math import *
print(eval('dir()', {}))
# Code dưới đây sẽ xảy ra exception
# print(eval('sqrt(25)', {}))
Nếu bạn truyền một dictionary trống vào global thì chỉ có hàm __builtins__ là hợp lệ với bieuthuc. Bạn sẽ không thể truy cập bất kì hàm nào thuộc module toán học mặc dù đã import module toán học vào chương trình ở phía trên.
Chạy chương trình, kết quả trả về là:
['__builtins__']
Còn ở ví dụ này, biểu thức có thể sử dụng các hàm sqrt() và pow() cùng với __builtins__.
from math import *
print(eval('dir()', {'sqrt': sqrt, 'pow': pow}))
Ngoài ra, có thể thay đổi tên của phương thức có sẵn cho biểu thức theo mong muốn của bạn.
from math import *
print(eval('dir()', {'canbachai': sqrt, 'luythua': pow}))
# dùng canbachai trong biểu thức
print(eval('canbachai(9)', {'canbachai': sqrt, 'luythua': pow}))
Trường hợp truyền đủ cả tham số global và local
from math import *
a = 5
print(eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt}))
Chạy chương trình, kết quả trả về là
2.23606797749979
8 Th3 2021
22 Th3 2021
26 Th2 2021
26 Th2 2021
14 Th1 2021
17 Th1 2021