سطح مقدماتی (Beginner Level)
پایتون به عنوان یک زبان مفسری (Interpreted)، قابلیتی قدرتمند دارد که اجازه میدهد رشتههای متنی (Strings) را به عنوان کد پایتون اجرا کنید. این کار توسط دو تابع داخلی eval() و exec() انجام میشود. در این بخش با تفاوتهای این دو و کاربردهای ساده آنها آشنا میشویم.
۱. تابع eval (مخصوص عبارات)
تابع eval() مخفف Evaluate است. این تابع یک رشته را میگیرد و آن را به عنوان یک "عبارت" (Expression) پایتون ارزیابی میکند و نتیجه را برمیگرداند.
- نکته: عبارت کدی است که یک مقدار تولید میکند (مثل عملیات ریاضی، فراخوانی تابع، یا متغیر).
evalنمیتواند دستورات پیچیده مثل تعریف تابع (def) یا حلقه (for) را اجرا کند.
مثال اول: محاسبه ریاضی ساده
در این مثال یک رشته حاوی عملیات ریاضی را اجرا میکنیم.
مثال دوم: کار با متغیرها
شما میتوانید از متغیرهایی که در برنامه تعریف شدهاند، درون رشتهی eval استفاده کنید.
مثال سوم: محدودیت eval
اگر سعی کنید یک دستور (Statement) مثل انتساب متغیر (x = 5) را در eval اجرا کنید، با خطا مواجه میشوید.
۲. تابع exec (مخصوص دستورات)
تابع exec() مخفف Execute است. این تابع برای اجرای "دستورات" (Statements) و بلوکهای کد استفاده میشود.
execهیچ مقداری برنمیگرداند (همیشهNoneاست).- میتواند حلقهها، تعریف کلاس، تعریف تابع (
def)، و ایمپورتها را اجرا کند.
مثال اول: اجرای یک دستور ساده
در اینجا یک متغیر جدید را درون رشته تعریف میکنیم.
مثال دوم: اجرای بلوک کد (حلقه و شرط)
شما میتوانید چندین خط کد را با استفاده از Triple Quotes به exec بدهید.
مثال سوم: تعریف تابع به صورت پویا
میتوانید حتی یک تابع کامل را درون یک رشته بنویسید و آن را به برنامه اضافه کنید.
سطح پیشرفته (Professional Level)
استفاده از eval و exec در محیطهای حرفهای (Production) بسیار حساس است. بزرگترین چالش، امنیت و کنترل دسترسی (Scope) است. در این بخش یاد میگیریم چگونه محیط اجرای این توابع را ایزوله کنیم و از خطرات امنیتی جلوگیری کنیم.
۱. مدیریت Scope (Globals و Locals)
هر دو تابع eval و exec دو آرگومان اختیاری دیگر نیز میپذیرند:
globals: دیکشنری متغیرهای سراسری مجاز.locals: دیکشنری متغیرهای محلی مجاز.
اگر اینها را محدود نکنید، کد مخرب میتواند به تمام متغیرهای برنامه شما و حتی ماژولهای ایمپورت شده (مثل os) دسترسی داشته باشد.
مثال اول: محدود کردن دسترسی به متغیرها
در این مثال، به eval اجازه نمیدهیم به متغیرهای مخفی (secret) دسترسی پیدا کند.
مثال دوم: تزریق توابع خاص
میتوانید فقط توابع خاصی (مثل توابع ریاضی) را در اختیار کد پویا قرار دهید و بقیه را حذف کنید.
۲. خطرات امنیتی (Injection Attacks)
شعار معروف برنامهنویسان پایتون این است: "Eval is Evil".
اگر ورودی کاربر را مستقیماً به eval یا exec بدهید، کاربر میتواند کدهای مخربی مثل حذف فایلها یا سرقت اطلاعات را اجرا کند.
مثال سناریوی خطرناک (تئوری)
کد زیر نشان میدهد چگونه یک کاربر مخرب میتواند ماژول os را ایمپورت کرده و دستورات سیستم عامل را اجرا کند (این کد فقط برای آموزش است و در محیط سندباکس اجرا نمیشود).
# Static Code: Security Risk Example
user_input = "__import__('os').system('rm -rf /')" # Danger!
# eval(user_input) # This would wipe files on a Linux system
۳. جایگزین امن: ast.literal_eval
اگر هدف شما فقط تبدیل یک رشته به ساختار داده پایتون (مثل تبدیل رشته "{'a': 1}" به دیکشنری) است، هرگز از eval استفاده نکنید. به جای آن از ماژول ast و تابع literal_eval استفاده کنید. این تابع فقط ساختارهای دادهای امن را ارزیابی میکند و اجازه اجرای توابع یا محاسبات را نمیدهد.
مثال مقایسه eval و literal_eval
۴. کامپایل کد با compile()
اگر نیاز دارید یک قطعه کد پویا را چندین بار اجرا کنید، استفاده مداوم از exec کند است زیرا هر بار کد را پارس (Parse) میکند. بهتر است ابتدا آن را با تابع compile() به یک آبجکت کد تبدیل کنید و سپس اجرا کنید.
