Trong hướng dẫn này, chúng ta sẽ tìm hiểu về phương thức eval() trong Python với sự trợ giúp của các ví dụ.
Các bài viết liên quan:
Ví dụ
#khai báo number = 9 number = 9 # eval thực hiện phép nhân được truyền dưới dạng đối số square_number = eval('number * number') print(square_number)
Cú pháp eval()
Cú pháp của eval() là:
eval(expression, globals=None, locals=None)
Tham số eval()
Hàm eval() nhận ba tham số:
- Expression – chuỗi được phân tích cú pháp và đánh giá dưới dạng biểu thức Python
- Globals(tùy chọn) – một từ điển
- locals (tùy chọn) – một đối tượng ánh xạ. Từ điển là loại ánh xạ tiêu chuẩn và thường được sử dụng trong Python.
Việc sử dụng global và local sẽ được thảo luận sau trong bài viết này.
Eval() Giá trị trả về
Phương thức eval() trả về kết quả được đánh giá từ biểu thức.
Ví dụ 1: Cách eval() hoạt động trong Python
x = 1 print(eval('x + 1'))
Ở đây, hàm eval() tính toán biểu thức x + 1 và print được sử dụng để hiển thị giá trị này.
Ví dụ 2: Ví dụ thực tế để chứng minh việc sử dụng eval()
# Chu Vi Hình Vuông def calculatePerimeter(l): return 4*l # Diện tích hình vuông def calculateArea(l): return l*l expression = input("Nhập một function: ") #duyệt range từ 1 đến 5 for l in range(1, 5): #nếu là chu vi thì tính toán chu vi if (expression == 'calculatePerimeter(l)'): print("nếu l =", l, ", Perimeter = ", eval(expression)) elif (expression == 'calculateArea(l)'): print("nếu l = ", l, ", Area = ", eval(expression)) else: print('Function không đúng') break
Cảnh báo khi sử dụng eval()
Hãy xem xét tình huống bạn đang sử dụng hệ thống Unix (macOS, Linux, v.v.) và bạn đã nhập mô-đun os. Mô-đun os cung cấp một cách di động để sử dụng các chức năng của hệ điều hành như đọc hoặc ghi vào tệp.
Nếu bạn cho phép người dùng nhập một giá trị bằng cách sử dụng eval(input()), thì người dùng có thể đưa ra các lệnh để thay đổi tệp hoặc thậm chí xóa tất cả các tệp bằng cách sử dụng lệnh: os.system(‘rm -rf *’).
Nếu bạn đang sử dụng eval(input()) trong code của mình, bạn nên kiểm tra những biến và phương thức nào mà người dùng có thể sử dụng. Bạn có thể xem các biến và phương thức nào khả dụng bằng phương thức dir().
from math import * print(eval('dir()'))
Hạn chế sử dụng các phương thức và biến có sẵn trong eval()
Thông thường, tất cả các phương thức và biến khả dụng được sử dụng trong biểu thức (tham số đầu tiên cho eval()) có thể không cần thiết hoặc thậm chí có thể có lỗ hổng bảo mật. Bạn có thể cần hạn chế sử dụng các phương thức và biến này cho eval(). Bạn có thể làm như vậy bằng cách chuyển các tham số cục bộ và cục bộ tùy chọn (từ điển) cho hàm eval().
- Khi cả hai tham số global và locals bị bỏ qua
Nếu cả hai tham số đều bị bỏ qua (như trong các ví dụ trước của chúng tôi), thì biểu thức đượ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 có sẵn bằng mã sau:
in(eval('dir()')
- Truyền tham số global; tham số local bị bỏ qua
Các tham số globals và local (từ điển) được sử dụng tương ứng cho các biến globals và biến local. Nếu từ điển local bị bỏ qua, nó sẽ mặc định là từ điển global. Có nghĩa là, globals sẽ được sử dụng cho cả biến globals và biến local.
Lưu ý: Bạn có thể kiểm tra từ điển toàn cầu và cục bộ hiện tại trong Python bằng cách sử dụng các phương thức tích hợp globals() vàlocals() tương ứng.
Ví dụ 3: Chuyển empty dictionary làm tham số toàn cầu
from math import * print(eval('dir()', {})) # Mã sẽ đưa ra một ngoại lệ print(eval('sqrt(25)', {}))
['__builtins__'] Traceback (most recent call last): File "<string>", line 5, in <module> print(eval('sqrt(25)', {})) File "<string>", line 1, in <module> NameError: name 'sqrt' is not defined
Nếu bạn chuyển một từ điển trống dưới dạng toàn cục, thì chỉ có __buildins__ khả dụng cho biểu thức (tham số đầu tiên cho eval()).
Mặc dù chúng ta đã nhập mô-đun toán học trong chương trình trên, nhưng biểu thức không thể truy cập bất kỳ chức năng nào do mô-đun toán học cung cấp.
Ví dụ 4: Cung cấp một số Phương thức nhất định
from math import * print(eval('dir()', {'sqrt': sqrt, 'pow': pow}))
Ở đây, biểu thức chỉ có thể sử dụng phương thức sqrt() và pow() với __buildins__.
Cũng có thể thay đổi tên của phương thức có sẵn cho biểu thức theo ý muốn của bạn:
from math import * names = {'square_root': sqrt, 'power': pow} print(eval('dir()', names)) # Sử dụng căn bậc hai trong Biểu thức print(eval('square_root(9)', names))
Trong chương trình trên, square_root() tính căn bậc hai bằng cách sử dụng sqrt(). Tuy nhiên, cố gắng sử dụng trực tiếp sqrt() sẽ gây ra lỗi.
Ví dụ 5: Hạn chế sử dụng tích hợp sẵn
Bạn có thể hạn chế việc sử dụng __buildins__ trong biểu thức như sau:
eval(expression, {'__builtins__': None})
- Vượt qua cả từ điển global và local
Bạn có thể cung cấp các hàm và biến cần thiết để sử dụng bằng cách chuyển từ điển địa phương. Ví dụ:
from math import * a = 169 print(eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt}))
Trong chương trình này, biểu thức chỉ có thể có phương thức sqrt() và biến a. Tất cả các phương thức và biến khác đều không khả dụng.
Việc hạn chế sử dụng eval() bằng cách chuyển các từ điển toàn cầu và cục bộ sẽ giúp mã của bạn an toàn hơn, đặc biệt khi bạn đang sử dụng đầu vào do người dùng cung cấp cho phương thức eval().
Lưu ý: Đôi khi, eval() không an toàn ngay cả với các tên giới hạn. Khi một đối tượng và các phương thức của nó có thể truy cập được, hầu hết mọi thứ đều có thể được thực hiện. Cách an toàn duy nhất là xác thực đầu vào của người dùng.