Hàm exec() trong Python

Hàm exec() sử dụng để thực thi chương trình Python được tạo động có thể là chuỗi hoặc mã đối tượng. Cú pháp của hàm exec() như thế nào, nó có những tham số gì và cách sử dụng ra sao? Mời bạn đọc theo dõi.

Cú pháp hàm exec() trong Python

exec(doituong, global, local)

Các tham số của hàm exec():

Hàm exec() có ba tham số:

  • doituong: một chuỗi hoặc mã đối tượng
  • global: một dictionary chỉ định các phương thức và biến global có sẵn. Global là tham số không bắt buộc.
  • local: một đối tượng ánh xạ. Local là tham số không bắt buộc.

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.

Ví dụ 1: Hàm exec() hoạt động thế nào?

# được viết bởi Quantrimang.com
program = 'a = 5\nb=10\nprint("Tổng =", a+b)'
exec(program)

Chạy chương trình, kết quả trả về là:

Tổng = 15

Ở ví dụ này, chuỗi đối tượng được truyền vào exec(), tham số global và local được bỏ qua trong trường hợp này.

Ví dụ 2: Cho phép người dùng nhập input

program = input('Enter a program:')
exec(program)

Chạy chương trình, kết quả trả về là:

Enter a program: [print(item) for item in [1, 2, 3]]
1
2
3

Nếu bạn muốn lấy code Python từ người dùng, bạn có thể sử dụng hàm compile() trước khi sử dụng exec().

Bạn nên cẩn thận khi sử dụng exec!

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à exec(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 exec(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 *
exec('print(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 exec() 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.

Trường hợp truyền tham số global và bỏ qua local

Các tham số globallocal (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 tham số 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()local()

Ví dụ: Truyền một dictionary trống vào tham số global

from math import *
exec('print(dir())', {})

# Code dưới đây sẽ xảy ra exception
# print(exec('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 doituong. 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()pow() cùng với __builtins__.

from math import *
exec('print(dir())', {'sqrt': sqrt, 'pow': pow})

exec('print(sqrt(9))', {'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 *
exec('print(dir())', {'canbachai': sqrt, 'pow': pow})

# object can have canbachai() module
exec('print(canbachai(9))', {'canbachai': sqrt, 'pow': pow})

Trường hợp truyền đủ cả tham số global và local

from math import *

globalsParameter = {'__builtins__' : None}
localsParameter = {'print': print, 'dir': dir}
exec('print(dir())', globalsParameter, localsParameter)

Chạy chương trình, kết quả trả về là

['dir', 'print']

Ở đây, chỉ có hai hàm tích hợp sẵn print()dir() có thể được thực thi bởi hàm exec().

Điều quan trọng cần lưu ý là exec() thực thi nhưng không trả về bất kỳ giá trị nào (trả về None). Do đó, bạn không thể sử dụng các câu lệnh returnyield bên ngoài các hàm được định nghĩa.

Bài trước: Hàm float() trong Python

Bài tiếp: Hàm hex() trong Python

Thứ Sáu, 01/03/2019 09:43
53 👨 212