Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

Python exec(): รันโค้ดจากสตริง (Execute String as Code)

exec() เป็น Built-in Function ที่ Execute Python Code จาก String หรือ Code Object แตกต่างจาก eval() ที่ประเมิน Expression (คืนค่า) exec() รัน Statements (Assignment, Loops, Function Definitions, etc.) และคืนค่า None เสมอ

ไวยากรณ์

exec(source, globals=None, locals=None)
  • source: String หรือ Code Object
  • globals: Global Namespace (Dict)
  • locals: Local Namespace (Dict)

ตัวอย่างพื้นฐาน

1. Execute Simple Statement

code = 'x = 10\ny = 20\nprint(f"x + y = {x + y}")'
exec(code)
# Output: x + y = 30

2. Multi-line String (Triple Quotes)

code = """
numbers = [11, 33, 55, 39, 55, 75, 37, 21, 23, 41, 13]
for num in numbers:
    if num % 2 == 0:
        print('Found even number:', num)
        break
else:
    print('No even number found')
"""

exec(code)
# Output: No even number found

3. Dynamic Function Definition

func_code = """
def greet(name):
    return f'Hello, {name}!'

def add(a, b):
    return a + b
"""

exec(func_code)

# ฟังก์ชันพร้อมใช้งานใน Global Scope
print(greet("World"))  # Hello, World!
print(add(5, 3))       # 8

Namespace Control: Globals และ Locals

1. Default Behavior (ใช้ Current Scope)

x = 100
exec('x = 200')  # แก้ไข x ใน Global Scope
print(x)  # 200

2. Isolated Namespace (แนะนำสำหรับ Security)

# สร้าง Namespace ใหม่
custom_globals = {}
custom_locals = {}

code = """
x = 10
y = 20
result = x + y
"""

exec(code, custom_globals, custom_locals)

print(custom_locals['result'])  # 30
print('x' in globals())  # False (ไม่ปนเปื้อน Global Scope)

3. Restricted Built-ins (Security)

# จำกัด Built-ins
restricted_globals = {"__builtins__": {}}
restricted_locals = {"allowed_func": len, "data": [1,2,3]}

code = "result = allowed_func(data)"
exec(code, restricted_globals, restricted_locals)
print(restricted_locals['result'])  # 3

# พยายามเข้าถึงอันตราย
try:
    exec("__import__('os').system('ls')", restricted_globals, restricted_locals)
except NameError:
    print("Blocked!")

⚠️ Security Warning (สำคัญมาก)

exec() อันตรายเท่า eval() หรือมากกว่า เพราะรัน Statements ได้ทุกอย่าง:

  • ลบไฟล์: exec("import os; os.remove('important.txt')")
  • อ่านไฟล์: exec("print(open('/etc/passwd').read())")
  • Network Access, Process Spawning, etc.

Best Practices สำหรับการใช้งานปลอดภัย

1. ไม่ใช้กับ User Input โดยตรง

# ❌ อันตราย
user_code = input("Enter code: ")
exec(user_code)

# ✅ ปลอดภัยกว่า: ใช้ Allowlist
allowed_commands = {
    'print': print,
    'len': len,
    'sum': sum,
}

user_input = input("Enter expression: ")
# Parse และ Validate ก่อน Exec

2. ใช้ Compile() ก่อน (Optional)

code_str = "x = 1\ny = 2\nprint(x+y)"

# Compile First (Syntax Check)
compiled_code = compile(code_str, '', 'exec')

# Execute Compiled Code
exec(compiled_code, {}, {})

3. Sandboxing Libraries

  • RestrictedPython - Restricted Execution Environment
  • PyPy Sandbox - Sandboxed PyPy
  • Docker/Containers - OS-level Isolation

กรณีใช้งานที่เหมาะสม (Legitimate Use Cases)

  • Dynamic Plugin/Extension System (Trusted Sources)
  • Code Generation Tools (Template -> Code)
  • Interactive Python Shells / Notebooks
  • Configuration as Code (กับ Validation)
  • Testing Frameworks (Dynamic Test Generation)

สรุป

  • exec() รัน Statements, eval() ประเมิน Expressions
  • คืนค่า None เสมอ
  • Security Risk สูงมาก - ไม่ใช้กับ Untrusted Input
  • ใช้ Namespace Isolation (globals, locals) และ Restrict Built-ins
  • พิจารณาทางเลือก: importlib, ast.literal_eval, simpleeval, Plugin Architectures