flask

مفهوم روت، هندلر و دکوراتورها

مفهوم روت در برنامه نویسی وب

 روت (Route) در برنامه نویسی وب، به آدرس اینترنتی خاصی گفته می‌شود که به یک بخش خاص از یک برنامه وب اشاره دارد. به عبارت ساده‌تر، روت‌ها نقش راهنما را برای مرورگر ایفا می‌کنند تا بداند وقتی کاربر یک آدرس خاص را وارد می‌کند، کدام بخش از کد باید اجرا شود.

تشبیه به یک ساختمان

برای درک بهتر مفهوم روت، می‌توانیم آن را به یک ساختمان تشبیه کنیم. هر اتاق در یک ساختمان را می‌توان به یک روت تشبیه کرد. آدرس هر اتاق (مثلاً طبقه دوم، اتاق شماره ۱۰) مانند آدرس یک روت است. وقتی کسی می‌خواهد به اتاق خاصی برود، آدرس آن اتاق را به او می‌دهیم تا بتواند به راحتی آن را پیدا کند.

مثال در فلاسک

در فلاسک، یک فریمورک پایتون برای ساخت برنامه‌های وب، روت‌ها به صورت زیر تعریف می‌شوند:

Python
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'سلام از صفحه اصلی!'

if __name__ == '__main__':
    app.run()

در این مثال:

  • @app.route('/'): این دکوراتور یک روت به آدرس / تعریف می‌کند. یعنی وقتی کاربری آدرس http://آدرس_سرور شما/ را در مرورگر خود وارد کند، این روت فعال می‌شود.
  • index(): این تابع هندلر برای روت / است. یعنی وقتی روت فعال شد، این تابع اجرا شده و متن “سلام از صفحه اصلی!” را به عنوان پاسخ به کاربر برمی‌گرداند.

اهمیت روت‌ها در برنامه نویسی وب

روت‌ها در برنامه نویسی وب مانند نشانی خانه‌ها هستند. هر خانه آدرس منحصر به فردی دارد تا افراد بتوانند آن را پیدا کنند. به همین ترتیب، هر صفحه یا بخش از یک وبسایت نیز آدرس منحصر به فردی دارد که به آن روت گفته می‌شود.

چرا روت‌ها مهم هستند؟

  1. ساختاردهی برنامه:
    • روت‌ها به شما کمک می‌کنند تا برنامه خود را به بخش‌های منطقی تقسیم کنید. هر روت نشان‌دهنده یک بخش خاص از برنامه است.
    • با استفاده از روت‌ها، می‌توانید به راحتی بفهمید که کدام بخش از کد مسئول نمایش یک صفحه خاص است.
  2. مدیریت درخواست‌های کاربر:
    • وقتی کاربری آدرسی را در مرورگر خود وارد می‌کند، در واقع درخواستی را به سرور ارسال می‌کند.
    • روت‌ها به سرور کمک می‌کنند تا این درخواست را به بخش صحیح از برنامه هدایت کند.
    • به عنوان مثال، اگر کاربری آدرس /محصولات را وارد کند، روتی که به این آدرس مرتبط است، کدی را اجرا می‌کند که لیست محصولات را نمایش می‌دهد.
  3. ایجاد URLهای قابل فهم:
    • روت‌ها به شما اجازه می‌دهند تا URLهای قابل فهم و معنی‌داری برای کاربران ایجاد کنید.
    • به عنوان مثال، به جای استفاده از URLهای پیچیده مانند /index.php?page=products, می‌توانید از URLهای ساده‌تر مانند /محصولات استفاده کنید.
  4. SEO:
    • روت‌های خوب به موتورهای جستجو کمک می‌کنند تا محتوای وبسایت شما را بهتر ایندکس کنند.
    • URLهای کوتاه، توصیفی و مرتبط با محتوا، به بهبود رتبه‌بندی وبسایت شما در نتایج جستجو کمک می‌کنند.
  5. توسعه‌پذیری:
    • با استفاده از روت‌ها، می‌توانید به راحتی قابلیت‌های جدیدی به وبسایت خود اضافه کنید.
    • برای اضافه کردن یک صفحه جدید، کافی است یک روت جدید تعریف کرده و یک هندلر برای آن بنویسید.

مثال:

فرض کنید یک وبسایت فروشگاهی دارید. شما می‌توانید روت‌های زیر را تعریف کنید:

  • /: صفحه اصلی سایت
  • /محصولات: صفحه نمایش محصولات
  • /محصولات/<id>: صفحه جزئیات یک محصول خاص (که در آن <id> شناسه محصول است)
  • /سبد-خرید: صفحه سبد خرید
  • /ثبت-نام: صفحه ثبت نام کاربر

در خلاصه:

روت‌ها نقشی اساسی در سازماندهی و مدیریت برنامه‌های وب ایفا می‌کنند. با استفاده از روت‌ها، می‌توانید برنامه‌های وب کارآمدتر، قابل نگهداری و مقیاس‌پذیرتری ایجاد کنید.

انواع روت‌ها

در برنامه‌نویسی وب با فلاسک، روت‌ها نقش مهمی در هدایت درخواست‌های کاربر به قسمت‌های مختلف برنامه ایفا می‌کنند. روت‌ها به دو دسته اصلی تقسیم می‌شوند:

روت‌های استاتیک (Static Routes)

    • تعریف: روت‌های استاتیک آدرس‌هایی با ساختار ثابت و از پیش تعریف شده هستند. این آدرس‌ها هیچ گونه پارامتری را شامل نمی‌شوند و همیشه به یک بخش خاص از برنامه اشاره می‌کنند.

    • مثال:

      Python
      from flask import Flask
      
      app = Flask(__name__)
      
      @app.route('/')
      def index():
          return 'صفحه اصلی'
      
      @app.route('/about')
      def about():
          return 'درباره ما'

      در این مثال، روت / همیشه به تابع index و روت /about همیشه به تابع about اشاره می‌کند.

    • ویژگی‌ها:

      • ساختار ساده و قابل پیش‌بینی
      • مناسب برای صفحات ثابت و محتواهایی که به ندرت تغییر می‌کنند

روت‌های دینامیک (Dynamic Routes)

    • تعریف: روت‌های دینامیک آدرس‌هایی هستند که شامل بخش‌های متغیر یا پارامترهایی هستند. این پارامترها می‌توانند مقادیر مختلفی را بگیرند و به شما اجازه می‌دهند تا با یک روت، به صفحات متفاوتی دسترسی پیدا کنید.

    • مثال:

      Python
      from flask import Flask
      
      app = Flask(__name__)
      
      @app.route('/users/<username>')
      def user_profile(username):
          return f'پروفایل کاربری {username}'

      در این مثال، <username> یک پارامتر است که می‌تواند هر نام کاربری باشد. وقتی کاربری آدرسی مانند /users/ali را وارد کند، پارامتر username مقدار ali را می‌گیرد و تابع user_profile با این مقدار فراخوانی می‌شود.

    • ویژگی‌ها:

      • انعطاف‌پذیری بالا
      • مناسب برای ایجاد URLهای پویا و نمایش محتواهای مختلف بر اساس پارامترهای ورودی
      • برای ساخت صفحات جزئیات، صفحات جستجو و … بسیار مفید است

تفاوت‌های کلیدی

ویژگی روت‌های استاتیک روت‌های دینامیک
ساختار ثابت و از پیش تعریف شده شامل پارامترهای متغیر
انعطاف‌پذیری پایین بالا
کاربرد صفحات ثابت، محتواهای پایدار صفحات دینامیک، صفحات جزئیات، جستجو
مثال /about, /contact /products/<product_id>, /users/<username>

انتخاب نوع روت مناسب

  • روت‌های استاتیک: برای صفحاتی که محتوا یا ساختار آن‌ها به ندرت تغییر می‌کند مناسب‌تر هستند.
  • روت‌های دینامیک: برای صفحاتی که محتوای آن‌ها بر اساس پارامترهای ورودی تغییر می‌کند و یا برای ایجاد URLهای قابل فهم‌تر و SEO-friendly مناسب‌تر هستند.

در انتخاب نوع روت، به موارد زیر توجه کنید:

  • نوع محتوایی که می‌خواهید نمایش دهید: آیا محتوا ثابت است یا بر اساس پارامترها تغییر می‌کند؟
  • نیازهای SEO: آیا می‌خواهید URLهای شما برای موتورهای جستجو قابل فهم باشند؟
  • ساختار برنامه شما: چگونه می‌خواهید برنامه خود را سازماندهی کنید؟

جمع‌بندی

درک تفاوت بین روت‌های استاتیک و دینامیک برای ساخت برنامه‌های وب با فلاسک بسیار مهم است. با انتخاب مناسب نوع روت، می‌توانید برنامه‌های وب کارآمدتر، قابل نگهداری و انعطاف‌پذیرتری ایجاد کنید.

جمع‌بندی

روت‌ها ستون فقرات برنامه‌های وب هستند و به شما کمک می‌کنند تا درخواست‌های کاربران را به درستی مدیریت کنید و تجربه کاربری بهتری را ارائه دهید. با درک مفهوم روت‌ها، می‌توانید برنامه‌های وب پیچیده‌تری را طراحی و توسعه دهید.

هندلر در فلاسک: قلب تپنده‌ی پاسخ‌گویی به درخواست‌ها

هندلر یا تابع دید (View function) در فلاسک، قلب تپنده‌ی پاسخ‌گویی به درخواست‌های کاربران است. زمانی که کاربری آدرسی را در مرورگر خود وارد می‌کند، فلاسک این آدرس را با روت‌های تعریف شده تطبیق می‌دهد و اگر روتی پیدا شود، هندلر مرتبط با آن روت فراخوانی می‌شود.

چه کاری انجام می‌دهد؟

هندلرها مسئولیت پردازش درخواست‌ها و تولید پاسخ‌های مناسب را بر عهده دارند. به طور خلاصه، یک هندلر:

  • درخواست را دریافت می‌کند: اطلاعاتی مانند روش درخواست (GET، POST، PUT، DELETE)، پارامترها، کوکی‌ها و داده‌های ارسالی در بدنه درخواست را بررسی می‌کند.
  • داده‌ها را پردازش می‌کند: ممکن است نیاز به دسترسی به پایگاه داده، اعتبارسنجی داده‌ها، انجام محاسبات یا هر عملیات دیگری داشته باشد.
  • پاسخ را تولید می‌کند: پس از پردازش درخواست، یک پاسخ HTTP تولید می‌کند که شامل کد وضعیت HTTP، سرآیندها و محتوای پاسخ است.

مثال ساده

Python
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'سلام از صفحه اصلی!'

در این مثال:

  • @app.route('/'): این دکوراتور یک روت به آدرس / تعریف می‌کند.
  • index(): این تابع هندلر برای روت / است. وقتی کاربری آدرس / را در مرورگر خود وارد کند، این تابع اجرا شده و متن “سلام از صفحه اصلی!” را به عنوان پاسخ برمی‌گرداند.

انواع هندلرها در فلاسک

در فلاسک، هندلرها (یا توابع دید) وظیفه پردازش درخواست‌های HTTP و تولید پاسخ‌های مناسب را بر عهده دارند. هندلرها را می‌توان بر اساس پیچیدگی و وظیفه آن‌ها به انواع مختلفی تقسیم کرد:

۱. هندلرهای ساده (Simple Handlers)

    • تعریف: این هندلرها برای نمایش صفحات ساده HTML یا متن استفاده می‌شوند.
    • مثال:
      Python
      from flask import Flask
      
      app = Flask(__name__)
      
      @app.route('/')
      def index():
          return 'سلام از صفحه اصلی!'
      
    • کاربرد: مناسب برای صفحات ثابت یا صفحات حاوی محتوای ساده.

۲. هندلرهای پیچیده (Complex Handlers)

    • تعریف: این هندلرها برای انجام عملیات پیچیده‌تری مانند دسترسی به پایگاه داده، پردازش فرم‌ها، ایجاد صفحات دینامیک و … استفاده می‌شوند.
    • مثال:
      Python
      from flask import Flask, render_template
      
      app = Flask(__name__)
      
      @app.route('/users/<username>')
      def user_profile(username):
          # فرض کنید یک تابع برای دریافت اطلاعات کاربر از پایگاه داده داریم
          user_info = get_user_info(username)
          return render_template('user_profile.html', user=user_info)
      
    • کاربرد: مناسب برای ساخت صفحات پویا، صفحات شخصی، صفحات جستجو و …

۳. هندلرهای خطا (Error Handlers)

    • تعریف: این هندلرها برای مدیریت خطاهای مختلف استفاده می‌شوند. مثلاً هنگامی که کاربری آدرسی را وارد می‌کند که وجود ندارد، یک هندلر خطا فراخوانی می‌شود تا یک صفحه خطای ۴۰۴ را نمایش دهد.
    • مثال:
      Python
      @app.errorhandler(۴۰۴)
      def page_not_found(error):
          return render_template('۴۰۴.html'), ۴۰۴
      
    • کاربرد: برای ارائه تجربه کاربری بهتر و مدیریت خطاهای پیش‌بینی نشده.

۴. هندلرهای قبل از درخواست (Before Request Handlers)

    • تعریف: این هندلرها قبل از اجرای هندلر اصلی فراخوانی می‌شوند. آن‌ها می‌توانند برای انجام کارهایی مانند تأیید هویت، تنظیم متغیرهای جهانی یا ثبت وقایع استفاده شوند.
    • مثال:
      Python
      @app.before_request
      def before_request_func():
          # کدهایی که قبل از هر درخواست اجرا می‌شوند
          pass
      

۵. هندلرهای بعد از درخواست (After Request Handlers)

    • تعریف: این هندلرها بعد از اجرای هندلر اصلی فراخوانی می‌شوند. آن‌ها می‌توانند برای انجام کارهایی مانند بسته شدن اتصالات پایگاه داده یا ثبت وقایع استفاده شوند.
    • مثال:
      Python
      @app.after_request
      def after_request_func(response):
          # کدهایی که بعد از هر درخواست اجرا می‌شوند
          return response
      

انتخاب نوع هندلر مناسب

  • سادگی و پیچیدگی عملیات: برای عملیات ساده، هندلرهای ساده کافی هستند. برای عملیات پیچیده، هندلرهای پیچیده مورد نیاز است.
  • نوع خطایی که انتظار دارید: برای هر نوع خطا، هندلر خطای مناسب را تعریف کنید.
  • زمان اجرای کد: اگر کدی نیاز است قبل یا بعد از هر درخواست اجرا شود، از هندلرهای قبل یا بعد از درخواست استفاده کنید.

در انتخاب نوع هندلر، به موارد زیر توجه کنید:

  • خوانایی کد: هندلرها باید به خوبی سازماندهی شده و قابل فهم باشند.
  • کارایی: هندلرها نباید باعث کاهش سرعت برنامه شوند.
  • انعطاف‌پذیری: هندلرها باید به گونه‌ای طراحی شوند که بتوان آن‌ها را به راحتی تغییر داد و توسعه داد.

با انتخاب مناسب نوع هندلر، می‌توانید برنامه‌های وب فلاسک خود را بهینه سازی کرده و قابلیت‌های جدیدی به آن اضافه کنید.

 

اهمیت هندلرها

  • هندلرها (یا توابع دید) قلب تپنده‌ی هر برنامه وب هستند. آن‌ها وظیفه پردازش درخواست‌های کاربران و تولید پاسخ‌های مناسب را بر عهده دارند. به عبارت ساده‌تر، هر بار که شما آدرسی را در مرورگر خود تایپ می‌کنید و منتظر نتیجه می‌مانید، یک هندلر در پشت صحنه مشغول کار است تا به درخواست شما پاسخ دهد.

    چرا هندلرها اینقدر مهم هستند؟

    • ساختاردهی برنامه: هندلرها به شما کمک می‌کنند تا برنامه خود را به بخش‌های منطقی تقسیم کنید. هر هندلر یک وظیفه خاص را انجام می‌دهد و این باعث می‌شود که کد شما قابل فهم‌تر و نگهداری‌اش آسان‌تر شود.
    • مدیریت درخواست‌ها: وقتی کاربری درخواستی را ارسال می‌کند، هندلر مناسب برای آن درخواست فراخوانی می‌شود. این باعث می‌شود که درخواست‌ها به درستی پردازش شوند و پاسخ‌های صحیح به کاربران ارسال شود.
    • تولید پاسخ‌های دینامیک: هندلرها می‌توانند پاسخ‌های متفاوتی را بر اساس شرایط مختلف تولید کنند. به عنوان مثال، یک هندلر می‌تواند بسته به اینکه کاربر لاگین کرده است یا خیر، صفحات مختلفی را نمایش دهد.
    • توسعه‌پذیری: با اضافه کردن هندلرهای جدید، می‌توانید به راحتی قابلیت‌های برنامه خود را گسترش دهید.

    مثال ساده:

    فرض کنید شما یک وبسایت فروشگاهی دارید. شما می‌توانید هندلرهایی برای صفحات زیر تعریف کنید:

    • صفحه اصلی: نمایش محصولات پرفروش
    • صفحه محصولات: نمایش لیست کامل محصولات
    • صفحه محصول: نمایش جزئیات یک محصول خاص
    • صفحه سبد خرید: نمایش محصولات انتخاب شده توسط کاربر
    • صفحه پرداخت: پردازش پرداخت

    به طور خلاصه:

    هندلرها نقش بسیار مهمی در برنامه‌نویسی وب ایفا می‌کنند. آن‌ها به شما کمک می‌کنند تا برنامه‌های وب کارآمد، قابل نگهداری و انعطاف‌پذیرتری ایجاد کنید.

نکات کلیدی

  • دکوراتور @app.route: برای اتصال یک تابع به یک روت استفاده می‌شود.
  • تابع بازگشتی: هندلر باید یک پاسخ HTTP را برگرداند که می‌تواند یک رشته، یک شیء قالب‌بندی شده یا یک پاسخ سفارشی باشد.
  • پارامترها: هندلرها می‌توانند پارامترهایی را دریافت کنند که از URL استخراج می‌شوند.
  • الگوها: برای ایجاد صفحات HTML دینامیک، می‌توانید از الگوها استفاده کنید.

جمع‌بندی

هندلرها قلب تپنده‌ی هر برنامه وب فلاسکی هستند. با درک نحوه کار هندلرها، می‌توانید برنامه‌های وب پویا و تعاملی ایجاد کنید که به نیازهای کاربران پاسخ دهند.

دکوراتور در فلاسک: تزئین توابع برای عملکردهای خاص

در برنامه‌نویسی با فلاسک، دکوراتورها (Decorators) ابزاری قدرتمند هستند که به شما اجازه می‌دهند تا رفتار توابع را بدون تغییر دادن کد اصلی آن‌ها تغییر دهید. به عبارت ساده‌تر، دکوراتورها مانند تزئیناتی هستند که بر روی توابع قرار می‌گیرند و ویژگی‌ها و قابلیت‌های جدیدی به آن‌ها اضافه می‌کنند.

انواع دکوراتورها: تزئیناتی برای توابع پایتون

دکوراتورها در پایتون مانند تزئیناتی هستند که بر روی توابع قرار می‌گیرند و رفتار آن‌ها را تغییر می‌دهند. این ابزار قدرتمند، به شما اجازه می‌دهد بدون تغییر کد اصلی تابع، قابلیت‌های جدیدی به آن اضافه کنید.

دسته‌بندی کلی دکوراتورها:

اگر بخواهیم دکوراتورها را به طور کلی دسته‌بندی کنیم، می‌توان آن‌ها را به دو دسته تقسیم کرد:

  1. دکوراتورهای داخلی پایتون: این دکوراتورها به صورت پیش‌ساخته در پایتون وجود دارند و برای انجام کارهای خاصی طراحی شده‌اند.
  2. دکوراتورهای سفارشی: شما می‌توانید دکوراتورهای خود را برای انجام کارهای خاص و سفارشی‌سازی شده ایجاد کنید.

دکوراتورهای داخلی پایتون: ابزارهای قدرتمند برای تزئین توابع

دکوراتورهای داخلی پایتون، توابعی از پیش تعریف شده هستند که به شما اجازه می‌دهند بدون تغییر کد اصلی یک تابع، رفتار آن را تغییر دهید. این دکوراتورها به عنوان تزئیناتی عمل می‌کنند که بر روی توابع قرار گرفته و قابلیت‌های جدیدی به آن‌ها اضافه می‌کنند.

انواع اصلی دکوراتورهای داخلی پایتون:

    • @staticmethod:
      • این دکوراتور یک متد را به یک متد استاتیک تبدیل می‌کند.
      • متدهای استاتیک نیازی به نمونه‌ای از کلاس ندارند و می‌توان آن‌ها را مستقیماً از طریق نام کلاس فراخوانی کرد.
      • معمولاً برای متدهایی استفاده می‌شود که به داده‌های خاصی از یک شیء نیاز ندارند.
    • @classmethod:
      • این دکوراتور یک متد را به یک متد کلاس تبدیل می‌کند.
      • متدهای کلاس به عنوان متدهای کلاس در نظر گرفته می‌شوند و می‌توانند به متغیرهای کلاس دسترسی داشته باشند.
      • معمولاً برای متدهایی استفاده می‌شود که به کلاس به عنوان یک کل عمل می‌کنند.
    • @property:
      • این دکوراتور یک متد را به یک ویژگی (attribute) تبدیل می‌کند.
      • با استفاده از این دکوراتور، می‌توانیم به یک متد به عنوان یک ویژگی دسترسی پیدا کنیم.
      • این کار باعث می‌شود که کد خواناتر و تمیزتر شود.
    • @abstractmethod:
      • این دکوراتور در برنامه‌نویسی شیء‌گرا استفاده می‌شود و یک متد را به عنوان یک متد انتزاعی مشخص می‌کند.
      • کلاس‌هایی که حاوی متدهای انتزاعی هستند، نمی‌توانند نمونه‌سازی شوند و باید توسط کلاس‌های فرزند پیاده‌سازی شوند.

مثال‌ها:

Python
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @staticmethod
    def is_adult(age):
        return age >= ۱۸

    @classmethod
    def from_string(cls, data):
        name, age = data.split(',')
        return cls(name, int(age))

    @property
    def full_name(self):
        return self.name

person1 = Person("علی", ۳۰)
print(person1.is_adult(۱۷))  # False
person2 = Person.from_string("حسین, ۲۵")
print(person2.full_name)  # حسین

کاربردهای دکوراتورهای داخلی:

    • ساده‌سازی کد: با استفاده از دکوراتورها، می‌توان کد را تمیزتر و خواناتر کرد.
    • افزودن قابلیت‌های جدید: دکوراتورها به شما اجازه می‌دهند بدون تغییر کد اصلی تابع، قابلیت‌های جدیدی به آن اضافه کنید.
    • ایجاد رابط‌های کاربری بهتر: دکوراتورها می‌توانند برای ایجاد رابط‌های کاربری بهتر و ساده‌تر استفاده شوند.
    • پیاده‌سازی الگوهای طراحی: برخی از الگوهای طراحی مانند Singleton با استفاده از دکوراتورها پیاده‌سازی می‌شوند.

جمع‌بندی:

دکوراتورهای داخلی پایتون ابزارهای قدرتمندی هستند که به شما اجازه می‌دهند کد خود را بهینه کرده و قابلیت‌های جدیدی به آن اضافه کنید. با درک نحوه کار این دکوراتورها، می‌توانید کدهای پایتون خود را به سطح بالاتری ببرید.

 

دکوراتورهای سفارشی در پایتون: تزئین توابع به سلیقه‌ی خودتان

دکوراتورهای سفارشی به شما این امکان را می‌دهند تا رفتار توابع خود را به صورت دلخواه تغییر دهید. این دکوراتورها در واقع توابعی هستند که توابع دیگر را به عنوان ورودی می‌گیرند و یک تابع جدید را برمی‌گردانند. این تابع جدید، رفتاری مشابه تابع اصلی دارد با این تفاوت که برخی عملیات اضافی نیز روی آن انجام می‌شود.

ساختار یک دکوراتور سفارشی:

Python
def my_decorator(func):
    def wrapper(*args, **kwargs):
        # کدهایی که قبل از اجرای تابع اصلی اجرا می‌شوند
        result = func(*args, **kwargs)
        # کدهایی که بعد از اجرای تابع اصلی اجرا می‌شوند
        return result
    return wrapper
  • func: تابعی که می‌خواهیم تزئین کنیم.
  • wrapper: تابعی که تابع اصلی را فراخوانی می‌کند و عملیات اضافی را انجام می‌دهد.
  • *args و **kwargs: برای ارسال آرگومان‌های نامشخص به تابع اصلی استفاده می‌شوند.

مثال عملی:

Python
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("قبل از اجرای تابع")
        result = func(*args, **kwargs)
        print("بعد از اجرای تابع")
        return result
    return wrapper

@my_decorator
def greet(name):
    print(f"سلام {name}!")

greet("علی")

در این مثال، دکوراتور my_decorator قبل و بعد از اجرای تابع greet، پیام‌هایی را چاپ می‌کند.

کاربردهای دکوراتورهای سفارشی:

  • ثبت وقایع (Logging): ثبت اطلاعاتی در مورد زمان اجرا، ورودی‌ها و خروجی‌های تابع
  • اندازه‌گیری زمان اجرا (Timing): محاسبه زمان اجرای یک تابع
  • حافظه پنهان (Caching): ذخیره نتایج یک تابع برای استفاده مجدد در آینده
  • تأیید هویت (Authentication): بررسی اعتبار کاربر قبل از اجرای تابع
  • اعتبارسنجی ورودی (Validation): بررسی صحت ورودی‌های یک تابع
  • مدیریت خطا (Error handling): مدیریت خطاهای احتمالی در هنگام اجرای تابع

مزایای استفاده از دکوراتورهای سفارشی:

  • افزایش خوانایی کد: با تفکیک نگرانی‌ها، کد شما خواناتر و قابل درک‌تر می‌شود.
  • کاهش تکرار کد: با استفاده از دکوراتورها، می‌توانید کدهای تکراری را به یک مکان منتقل کنید.
  • افزایش انعطاف‌پذیری: دکوراتورها به شما اجازه می‌دهند تا رفتار توابع را به صورت دینامیک تغییر دهید.

نکات مهم:

  • ترتیب دکوراتورها: اگر چندین دکوراتور روی یک تابع اعمال شود، ترتیب آن‌ها مهم است. دکوراتوری که در بالا قرار دارد، ابتدا اجرا می‌شود.
  • حفظ متادیتا: برای حفظ اطلاعاتی مانند نام تابع و رشته‌ی مستندسازی، می‌توانید از ماژول functools استفاده کنید.

مثال با استفاده از functools:

Python
from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # ...
        return func(*args, **kwargs)
    return wrapper   

جمع‌بندی:

دکوراتورهای سفارشی ابزاری قدرتمند برای تغییر رفتار توابع در پایتون هستند. با استفاده از آن‌ها می‌توانید کد خود را تمیزتر، انعطاف‌پذیرتر و قابل نگهداری‌تر کنید.

 

کاربردهای دکوراتورها:

دکوراتورها در پایتون ابزاری قدرتمند برای افزودن قابلیت‌های جدید به توابع بدون تغییر مستقیم کد آن‌ها هستند. این ابزار انعطاف‌پذیر، طیف وسیعی از کاربردها را در برنامه‌نویسی پایتون پوشش می‌دهد. در ادامه به برخی از مهم‌ترین کاربردهای دکوراتورها اشاره می‌کنیم:

۱. ثبت وقایع (Logging):

  • ردیابی جریان برنامه: با استفاده از دکوراتورها می‌توانیم اطلاعاتی مانند زمان شروع و پایان اجرای یک تابع، ورودی‌ها و خروجی‌های آن را ثبت کنیم. این اطلاعات برای اشکال‌زدایی و تحلیل عملکرد برنامه بسیار مفید است.
  • ایجاد گزارش: می‌توانیم گزارش‌هایی از فعالیت‌های برنامه ایجاد کنیم تا به راحتی بتوانیم عملکرد آن را بررسی کنیم.
کاربرد دکوراتورها: ثبت وقایع (Logging)

دکوراتورها در پایتون ابزاری قدرتمند برای افزودن قابلیت‌های جدید به توابع هستند، بدون آنکه نیاز به تغییر کد اصلی تابع باشد. یکی از کاربردهای مهم دکوراتورها، ثبت وقایع (Logging) است.

چرا ثبت وقایع مهم است؟
  • اشکال‌زدایی: با ثبت وقایعی مانند زمان شروع و پایان اجرای تابع، ورودی‌ها و خروجی‌ها، می‌توانیم به راحتی خطاها را شناسایی و برطرف کنیم.
  • تحلیل عملکرد: با بررسی لاگ‌ها می‌توانیم عملکرد برنامه را تحلیل کرده و نقاط ضعف آن را بهبود بخشیم.
  • امنیت: با ثبت فعالیت‌های کاربران، می‌توانیم به امنیت سیستم کمک کنیم.
  • نظارت: می‌توانیم با استفاده از لاگ‌ها بر عملکرد سیستم نظارت داشته باشیم.
چگونه از دکوراتورها برای ثبت وقایع استفاده کنیم؟

یک دکوراتور ساده برای ثبت وقایع می‌تواند به شکل زیر باشد:

Python
import logging
import time

def log_function_call(func):
    def wrapper(*args, **kwargs):
        logger = logging.getLogger(__name__)
        logger.info(f"Calling function: {func.__name__}")
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        logger.info(f"Function {func.__name__} finished in {end_time - start_time:f} seconds")
        return result
    return wrapper

@log_function_call
def my_function(x, y):
    # کدهای تابع
    time.sleep(۲)
    return x + y

در این مثال:

  • logger: یک شیء از کلاس logging.Logger است که برای ثبت پیام‌ها استفاده می‌شود.
  • start_time و end_time: برای محاسبه زمان اجرای تابع استفاده می‌شوند.
  • wrapper: تابع اصلی را فراخوانی می‌کند و قبل و بعد از آن پیام‌هایی را در لاگ ثبت می‌کند.
مزایای استفاده از دکوراتورها برای ثبت وقایع:
  • کاهش تکرار کد: کد ثبت وقایع در یک مکان متمرکز قرار می‌گیرد و نیازی به تکرار آن در هر تابع نیست.
  • افزایش خوانایی کد: کد اصلی تابع تمیزتر و خواناتر می‌شود.
  • انعطاف‌پذیری: می‌توانیم با تغییر تنظیمات لاگر، سطح جزئیات و مقصد ثبت وقایع را کنترل کنیم.
تنظیمات لاگر

برای تنظیم لاگر می‌توانیم از موارد زیر استفاده کنیم:

  • سطح لاگ: با استفاده از متدهای setLevel می‌توانیم سطح لاگ را تنظیم کنیم (مثلاً DEBUG, INFO, WARNING, ERROR).
  • فرمت لاگ: با استفاده از متد setFormatter می‌توانیم قالب پیام‌های لاگ را تغییر دهیم.
  • مقصد لاگ: می‌توانیم پیام‌های لاگ را به فایل، کنسول یا یک سیستم مدیریت لاگ مرکزی ارسال کنیم.
مثال پیشرفته:
Python
import logging
import time

logging.basicConfig(filename='my_log.log', level=logging.DEBUG,
                    format='%(asctime)s - %(levelname)s - %(message)s')

# ... بقیه کدها

در این مثال، پیام‌های لاگ با سطح DEBUG یا بالاتر در فایلی به نام my_log.log ذخیره می‌شوند.

جمع‌بندی: دکوراتورها ابزاری قدرتمند برای ثبت وقایع در پایتون هستند. با استفاده از دکوراتورها می‌توانیم به راحتی و به صورت خودکار اطلاعات مفیدی را در مورد اجرای برنامه ثبت کنیم و از این اطلاعات برای اشکال‌زدایی، تحلیل عملکرد و بهبود امنیت برنامه استفاده کنیم.

 

۲. اندازه‌گیری زمان اجرا (Timing):

  • بهینه‌سازی عملکرد: با اندازه‌گیری زمان اجرای توابع مختلف می‌توانیم بخش‌های کند برنامه را شناسایی کرده و آن‌ها را بهینه کنیم.
  • تحلیل الگوریتم‌ها: می‌توانیم عملکرد الگوریتم‌های مختلف را با هم مقایسه کنیم.
  • اندازه‌گیری زمان اجرا (Timing) با استفاده از دکوراتورها در پایتون

    دکوراتورها ابزاری قدرتمند در پایتون هستند که به شما اجازه می‌دهند بدون تغییر کد اصلی یک تابع، رفتار آن را تغییر دهید. یکی از کاربردهای مهم دکوراتورها، اندازه‌گیری زمان اجرای توابع است. با استفاده از این تکنیک، می‌توانید بخش‌های کند برنامه خود را شناسایی کرده و آن‌ها را بهینه کنید.

    چرا اندازه‌گیری زمان اجرا مهم است؟
    • بهینه‌سازی عملکرد: با شناسایی بخش‌هایی از کد که زمان زیادی را مصرف می‌کنند، می‌توانید تمرکز خود را بر روی بهینه‌سازی آن‌ها قرار دهید.
    • مقایسه الگوریتم‌ها: می‌توانید زمان اجرای الگوریتم‌های مختلف را مقایسه کرده و بهترین گزینه را انتخاب کنید.
    • تحلیل عملکرد: با اندازه‌گیری زمان اجرای توابع در شرایط مختلف، می‌توانید به درک بهتری از عملکرد برنامه خود برسید.
    ساخت یک دکوراتور برای اندازه‌گیری زمان اجرا
    Python
    import time
    from functools import wraps
    
    def timeit(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()   
            print(f"زمان اجرای تابع {func.__name__}: {end_time - start_time:f} ثانیه")
            return result
        return wrapper
    

    در این مثال:

    • timeit یک دکوراتور است که تابع دیگری را به عنوان ورودی می‌گیرد.
    • @wraps(func) از ماژول functools استفاده می‌کند تا متادیتای تابع اصلی حفظ شود.
    • wrapper تابع اصلی را فراخوانی می‌کند و قبل و بعد از اجرای آن، زمان را اندازه‌گیری می‌کند.
    استفاده از دکوراتور
    Python
    @timeit
    def my_function(x):
        # کدهای تابع
        time.sleep(۲)
        return x * x
    
    my_function(۵)
    

    در این مثال، دکوراتور timeit به تابع my_function اعمال شده است و زمان اجرای آن به صورت خودکار چاپ می‌شود.

    نکات مهم
    • دقت اندازه‌گیری: برای اندازه‌گیری‌های دقیق‌تر، می‌توانید از ماژول timeit استفاده کنید. این ماژول برای اندازه‌گیری زمان اجرای قطعات کوچک کد بسیار دقیق است.
    • تأثیر محیط: زمان اجرای یک تابع ممکن است تحت تأثیر عوامل مختلفی مانند بار پردازنده، حافظه و سایر منابع سیستم قرار گیرد. بنابراین، بهتر است اندازه‌گیری‌ها را چندین بار تکرار کنید و میانگین آن‌ها را محاسبه کنید.
    • اندازه گیری زمان اجرای بخش‌های مختلف کد: برای شناسایی دقیق‌تر بخش‌های کند یک تابع، می‌توانید از ابزارهای پروفایلینگ استفاده کنید.
    کاربردهای دیگر
    • مقایسه الگوریتم‌های مرتب‌سازی: می‌توانید زمان اجرای الگوریتم‌های مختلف مرتب‌سازی را مقایسه کنید.
    • بهینه‌سازی کوئری‌های پایگاه داده: می‌توانید زمان اجرای کوئری‌های پایگاه داده را اندازه‌گیری کرده و آن‌ها را بهینه کنید.
    • تحلیل عملکرد برنامه‌های وب: می‌توانید زمان پاسخگویی درخواست‌های HTTP را اندازه‌گیری کنید.

    با استفاده از دکوراتورهای اندازه‌گیری زمان اجرا، می‌توانید به صورت خودکار و دقیق عملکرد برنامه خود را تحلیل کرده و آن را بهینه کنید.

     

۳. حافظه پنهان (Caching):

  • بهبود عملکرد: با ذخیره نتایج محاسبات قبلی، می‌توان از محاسبه مجدد آن‌ها جلوگیری کرد و به این ترتیب عملکرد برنامه را بهبود بخشید.
  • کاهش بار سرور: در برنامه‌های وب، حافظه پنهان می‌تواند بار سرور را کاهش دهد.

 

  • حافظه پنهان (Caching) با استفاده از دکوراتورها در پایتون
    مقدمه

    حافظه پنهان (Caching) تکنیکی است که در آن نتایج محاسبات قبلی ذخیره می‌شوند تا در صورت نیاز مجدد، به جای تکرار محاسبات، از نتایج ذخیره شده استفاده شود. این کار به طور قابل توجهی می‌تواند عملکرد برنامه را بهبود بخشد، خصوصاً در مواردی که محاسبات زمان‌بر هستند.

    دکوراتورها در پایتون ابزاری قدرتمندی برای افزودن قابلیت‌های جدید به توابع هستند. با استفاده از دکوراتورها می‌توانیم به راحتی مکانیزم حافظه پنهان را به توابع خود اضافه کنیم.

    چرا از حافظه پنهان استفاده کنیم؟
    • افزایش سرعت: با ذخیره نتایج محاسبات قبلی، از تکرار محاسبات پرهزینه جلوگیری می‌شود.
    • کاهش بار سرور: در برنامه‌های وب، حافظه پنهان می‌تواند بار سرور را کاهش دهد.
    • بهبود تجربه کاربری: با کاهش زمان پاسخ‌گویی، تجربه کاربری بهبود می‌یابد.
    پیاده‌سازی حافظه پنهان با استفاده از دکوراتورها
    Python
    from functools import lru_cache
    
    def cache(maxsize=۱۲۸):
        return lru_cache(maxsize=maxsize)
    
    @cache
    def fibonacci(n):
        if n < ۲:
            return n
        return fibonacci(n-۱) + fibonacci(n-۲)
    

    در این مثال:

    • lru_cache یک دکوراتور داخلی در پایتون است که از الگوریتم Least Recently Used برای مدیریت حافظه پنهان استفاده می‌کند.
    • maxsize پارامتری است که حداکثر تعداد آیتم‌هایی که می‌توانند در حافظه پنهان ذخیره شوند را مشخص می‌کند.
    • تابع fibonacci با استفاده از دکوراتور cache تزئین شده است، بنابراین نتایج محاسبات قبلی این تابع در حافظه پنهان ذخیره می‌شوند.
    چگونه کار می‌کند؟

    هنگامی که تابع fibonacci فراخوانی می‌شود:

    1. ابتدا بررسی می‌شود که آیا نتیجه برای ورودی داده شده قبلاً محاسبه شده و در حافظه پنهان ذخیره شده است.
    2. اگر نتیجه در حافظه پنهان وجود داشته باشد، مستقیماً از آن برگردانده می‌شود.
    3. در غیر این صورت، تابع اجرا شده و نتیجه آن در حافظه پنهان ذخیره می‌شود تا در آینده مورد استفاده قرار گیرد.
    مزایای استفاده از lru_cache
    • سادگی: استفاده از lru_cache بسیار ساده است.
    • کارایی: الگوریتم LRU به طور مؤثری آیتم‌های کمتر استفاده شده را از حافظه پنهان حذف می‌کند.
    • انعطاف‌پذیری: با تنظیم پارامتر maxsize می‌توان اندازه حافظه پنهان را کنترل کرد.
    مثال پیشرفته‌تر
    Python
    from functools import lru_cache
    
    def expensive_calculation(a, b):
        # محاسبات پیچیده و زمان‌بر
        return a * b
    
    @cache(maxsize=۱۰۰۰)
    def my_function(x, y):
        result = expensive_calculation(x, y)
        return result
    

    در این مثال، تابع expensive_calculation محاسبات پیچیده‌ای انجام می‌دهد. با استفاده از دکوراتور cache، نتایج این محاسبات برای ورودی‌های مختلف در حافظه پنهان ذخیره می‌شوند و در صورت نیاز مجدد، از حافظه پنهان بازیابی می‌شوند.

    نکات مهم
    • انتخاب اندازه مناسب برای حافظه پنهان: اندازه حافظه پنهان باید به گونه‌ای انتخاب شود که هم به اندازه کافی بزرگ باشد تا بتواند نتایج محاسبات مهم را ذخیره کند و هم به اندازه کافی کوچک باشد تا از اشغال بیش از حد حافظه جلوگیری کند.
    • توجه به نوع داده‌ها: برخی از انواع داده‌ها مانند اشیاء قابل تغییر (mutable objects) ممکن است برای ذخیره در حافظه پنهان مناسب نباشند.
    • توجه به تغییرات داده‌ها: اگر داده‌های ورودی تابع تغییر کنند، باید حافظه پنهان را پاک یا به‌روزرسانی کرد.

    جمع‌بندی حافظه پنهان با استفاده از دکوراتورها یک ابزار قدرتمند برای بهبود عملکرد برنامه‌ها است. با استفاده از این تکنیک، می‌توانیم به طور قابل توجهی زمان اجرای برنامه‌های خود را کاهش دهیم و تجربه کاربری را بهبود بخشیم.

     

۴. تأیید هویت (Authentication):

  • کنترل دسترسی: می‌توانیم با استفاده از دکوراتورها، دسترسی به برخی توابع را محدود کنیم و تنها به کاربران مجاز اجازه اجرای آن‌ها را بدهیم.

 

  • تأیید هویت (Authentication) با استفاده از دکوراتورها در پایتون

    تأیید هویت فرآیندی است که در آن هویت یک شخص یا سیستم تأیید می‌شود. در برنامه‌نویسی، تأیید هویت به این معنی است که اطمینان حاصل کنیم کاربری که می‌خواهد به یک سیستم یا سرویس دسترسی پیدا کند، همان کسی است که ادعا می‌کند.

    دکوراتورها در پایتون ابزاری قدرتمندی هستند که به ما اجازه می‌دهند رفتار توابع را بدون تغییر در کد اصلی آن‌ها تغییر دهیم. با استفاده از دکوراتورها می‌توانیم مکانیزم تأیید هویت را به توابعی که نیاز به دسترسی محدود دارند، اضافه کنیم.

    چرا از دکوراتورها برای تأیید هویت استفاده کنیم؟
    • افزایش امنیت: با استفاده از دکوراتورها می‌توانیم به راحتی دسترسی به توابع حساس را محدود کنیم و تنها به کاربران مجاز اجازه دسترسی دهیم.
    • کاهش تکرار کد: کد تأیید هویت در یک مکان متمرکز قرار می‌گیرد و نیازی به تکرار آن در هر تابع نیست.
    • افزایش خوانایی کد: کد اصلی توابع تمیزتر و خواناتر می‌شود.
    پیاده‌سازی تأیید هویت با استفاده از دکوراتورها
    Python
    def authenticate(func):
        def wrapper(*args, **kwargs):
            username = input("نام کاربری خود را وارد کنید: ")
            password = input("رمز عبور خود را وارد کنید: ")
    
            # بررسی اعتبار نام کاربری و رمز عبور (مثلاً با استفاده از یک پایگاه داده)
            if username == "admin" and password == "password":
                return func(*args, **kwargs)
            else:
                print("نام کاربری یا رمز عبور اشتباه است.")
        return wrapper
    
    @authenticate
    def restricted_function():
        print("شما به این قسمت دسترسی دارید.")
    

    در این مثال:

    • authenticate یک دکوراتور است که تابع دیگری را به عنوان ورودی می‌گیرد.
    • wrapper تابع اصلی را فراخوانی می‌کند، اما قبل از آن از کاربر نام کاربری و رمز عبور می‌خواهد و اعتبار آن‌ها را بررسی می‌کند.
    • اگر نام کاربری و رمز عبور صحیح باشند، تابع اصلی اجرا می‌شود. در غیر این صورت، پیام خطا نمایش داده می‌شود.
    بهبود امنیت
    • رمزنگاری: برای ذخیره رمزهای عبور به صورت امن، از الگوریتم‌های رمزنگاری استفاده کنید.
    • حفاظت در برابر حملات: از تکنیک‌هایی مانند salt و hashing برای محافظت در برابر حملات دیکشنری و brute-force استفاده کنید.
    • استفاده از توکن‌های دسترسی: به جای ذخیره رمز عبور در حافظه، از توکن‌های دسترسی استفاده کنید.
    • محدود کردن تعداد تلاش‌های ناموفق: برای جلوگیری از حملات brute-force، تعداد تلاش‌های ناموفق را محدود کنید.
    مثال پیشرفته‌تر با استفاده از توکن‌های دسترسی
    Python
    import jwt
    from functools import wraps
    
    def authenticate(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            token = request.headers.get('Authorization')
            if not token:
                return jsonify({'message': 'Token is missing'}), ۴۰۱
    
            try:   
                data = jwt.decode(token, 'your_secret_key', algorithms=['HS256'])   
                user_id = data['user_id']
                # بررسی مجوزهای کاربر
                return func(*args, **kwargs)
            except jwt.ExpiredSignatureError:
                return jsonify({'message': 'Token has expired'}), ۴۰۱
            except jwt.InvalidTokenError:
                return jsonify({'message': 'Invalid token'}), ۴۰۱
        return wrapper   
    

    در این مثال، از توکن‌های JWT برای تأیید هویت استفاده می‌شود. توکن‌های JWT به صورت ایمن رمزنگاری شده‌اند و حاوی اطلاعاتی مانند شناسه کاربر و مجوزهای او هستند.

    جمع‌بندی دکوراتورها ابزاری قدرتمند برای پیاده‌سازی مکانیزم‌های تأیید هویت در پایتون هستند. با استفاده از دکوراتورها می‌توانیم به راحتی و به صورت یکپارچه، امنیت برنامه‌های خود را افزایش دهیم.

    نکات مهم:

    • پیاده‌سازی یک سیستم تأیید هویت کامل: پیاده‌سازی یک سیستم تأیید هویت کامل نیازمند توجه به بسیاری از جوانب امنیتی است.
    • استفاده از کتابخانه‌های آماده: برای پیاده‌سازی سیستم‌های تأیید هویت پیچیده، می‌توانید از کتابخانه‌های آماده مانند Flask-JWT-Extended استفاده کنید.

     

۵. اعتبارسنجی ورودی (Validation):

  • اطمینان از صحت داده‌ها: می‌توانیم با استفاده از دکوراتورها، ورودی‌های توابع را قبل از اجرا اعتبارسنجی کنیم تا از بروز خطاهای ناشی از داده‌های نامعتبر جلوگیری کنیم.

 

  • اعتبارسنجی ورودی (Validation) با استفاده از دکوراتورها در پایتون

    اعتبارسنجی ورودی فرآیندی است که در آن داده‌های ورودی یک برنامه بررسی می‌شوند تا اطمینان حاصل شود که معتبر و قابل استفاده هستند. این فرآیند به جلوگیری از خطاها و مشکلات امنیتی کمک می‌کند.

    دکوراتورها در پایتون ابزاری قدرتمندی هستند که به ما اجازه می‌دهند رفتار توابع را بدون تغییر در کد اصلی آن‌ها تغییر دهیم. با استفاده از دکوراتورها می‌توانیم مکانیزم اعتبارسنجی ورودی را به توابعی که نیاز به بررسی داده‌های ورودی دارند، اضافه کنیم.

    چرا از دکوراتورها برای اعتبارسنجی ورودی استفاده کنیم؟

    • افزایش کیفیت داده: با اعتبارسنجی ورودی، می‌توانیم اطمینان حاصل کنیم که داده‌های ورودی معتبر هستند و از بروز خطاها جلوگیری کنیم.
    • کاهش تکرار کد: کد اعتبارسنجی ورودی در یک مکان متمرکز قرار می‌گیرد و نیازی به تکرار آن در هر تابع نیست.
    • افزایش خوانایی کد: کد اصلی توابع تمیزتر و خواناتر می‌شود.

    پیاده‌سازی اعتبارسنجی ورودی با استفاده از دکوراتورها

    Python
    def validate_input(func):
        def wrapper(*args, **kwargs):
            # بررسی اعتبار ورودی‌ها
            if not isinstance(args[۰], int):
                raise ValueError("ورودی اول باید یک عدد صحیح باشد.")
            if args[۰] < ۰:
                raise ValueError("ورودی اول باید مثبت باشد.")
    
            return func(*args, **kwargs)
        return wrapper
    
    @validate_input
    def my_function(x):
        # کدهای تابع
        return x * x
    

    در این مثال:

    • validate_input یک دکوراتور است که تابع دیگری را به عنوان ورودی می‌گیرد.
    • wrapper تابع اصلی را فراخوانی می‌کند، اما قبل از آن ورودی‌ها را بررسی می‌کند.
    • اگر ورودی‌ها معتبر نباشند، یک استثناء (exception) ایجاد می‌شود.

    مثال پیشرفته‌تر با استفاده از کتابخانه typing

    Python
    from typing import Callable, Union
    
    def validate_input(func: Callable[..., Union[int, float]]) -> Callable[..., Union[int, float]]:
        def wrapper(*args, **kwargs):
            # بررسی نوع ورودی‌ها
            for arg in args:
                if not isinstance(arg, (int, float)):
                    raise TypeError("ورودی‌ها باید از نوع عدد صحیح یا اعشاری باشند.")
    
            return func(*args, **kwargs)
        return wrapper
    
    @validate_input
    def my_function(x: Union[int, float], y: Union[int, float]) -> Union[int, float]:
        # کدهای تابع
        return x + y
    

    در این مثال، از کتابخانه typing برای مشخص کردن نوع ورودی‌ها و خروجی تابع استفاده شده است. این باعث می‌شود کد خواناتر و قابل نگهداری‌تر شود.

    نکات مهم

    • استفاده از استثناءها: برای نشان دادن خطاهای اعتبارسنجی، از استثناءها استفاده کنید.
    • پیاده‌سازی قوانین اعتبارسنجی: قوانین اعتبارسنجی باید بر اساس نیازهای برنامه شما تعیین شوند.
    • استفاده از کتابخانه‌های آماده: برای پیاده‌سازی قوانین اعتبارسنجی پیچیده، می‌توانید از کتابخانه‌های آماده مانند schema یا marshmallow استفاده کنید.

    جمع‌بندی دکوراتورها ابزاری قدرتمند برای پیاده‌سازی مکانیزم‌های اعتبارسنجی ورودی در پایتون هستند. با استفاده از دکوراتورها می‌توانیم به راحتی و به صورت یکپارچه، کیفیت داده‌های ورودی برنامه‌های خود را بهبود بخشیم.

     

۶. مدیریت خطا (Error handling):

  • دستکاری خطاها: می‌توانیم با استفاده از دکوراتورها، خطاهای احتمالی را مدیریت کنیم و پیام‌های خطای سفارشی نمایش دهیم.

 

  • مدیریت خطا (Error handling) با استفاده از دکوراتورها در پایتون

    مدیریت خطا فرآیندی است که در آن برنامه‌ها به طور مناسب با خطاها و استثناءها برخورد می‌کنند. این فرآیند به جلوگیری از خرابی برنامه و ارائه تجربه کاربری بهتر کمک می‌کند.

    دکوراتورها در پایتون ابزاری قدرتمندی هستند که به ما اجازه می‌دهند رفتار توابع را بدون تغییر در کد اصلی آن‌ها تغییر دهیم. با استفاده از دکوراتورها می‌توانیم مکانیزم مدیریت خطا را به توابعی که ممکن است خطاهایی را ایجاد کنند، اضافه کنیم.

    چرا از دکوراتورها برای مدیریت خطا استفاده کنیم؟
    • افزایش پایداری: با مدیریت خطاها، می‌توانیم از خرابی برنامه جلوگیری کنیم و تجربه کاربری را بهبود بخشیم.
    • کاهش تکرار کد: کد مدیریت خطا در یک مکان متمرکز قرار می‌گیرد و نیازی به تکرار آن در هر تابع نیست.
    • افزایش خوانایی کد: کد اصلی توابع تمیزتر و خواناتر می‌شود.
    پیاده‌سازی مدیریت خطا با استفاده از دکوراتورها
    Python
    def handle_errors(func):
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except ZeroDivisionError:
                print("خطای تقسیم بر صفر!")
            except ValueError:
                print("ورودی نامعتبر!")
            except Exception as e:
                print(f"خطای غیرمنتظره: {e}")
        return wrapper
    
    @handle_errors
    def my_function(x, y):
        return x / y
    

    در این مثال:

    • handle_errors یک دکوراتور است که تابع دیگری را به عنوان ورودی می‌گیرد.
    • wrapper تابع اصلی را فراخوانی می‌کند، اما در یک بلوک try-except قرار می‌دهد.
    • اگر خطایی رخ دهد، استثناء مربوطه مدیریت می‌شود و یک پیام مناسب نمایش داده می‌شود.
    مثال پیشرفته‌تر با استفاده از کتابخانه logging
    Python
    import logging
    
    def handle_errors(func):
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                logging.error(f"خطای غیرمنتظره: {e}")
        return wrapper
    
    @handle_errors
    def my_function(x, y):
        # کدهای تابع
        return x / y
    

    در این مثال، از کتابخانه logging برای ثبت خطاها استفاده شده است. این باعث می‌شود بتوانیم خطاها را به صورت متمرکز بررسی و تحلیل کنیم.

    نکات مهم
    • انتخاب استثناءهای مناسب: استثناءهایی را انتخاب کنید که به خوبی خطاهای مختلف را توصیف می‌کنند.
    • پیاده‌سازی منطق مدیریت خطا: منطق مدیریت خطا باید بر اساس نیازهای برنامه شما تعیین شود.
    • استفاده از کتابخانه‌های آماده: برای پیاده‌سازی مکانیزم‌های مدیریت خطا پیچیده، می‌توانید از کتابخانه‌های آماده مانند traceback استفاده کنید.

    جمع‌بندی دکوراتورها ابزاری قدرتمند برای پیاده‌سازی مکانیزم‌های مدیریت خطا در پایتون هستند. با استفاده از دکوراتورها می‌توانیم به راحتی و به صورت یکپارچه، پایداری برنامه‌های خود را افزایش دهیم.

     

۷. تزئین کلاس‌ها:

  • افزودن قابلیت‌های جدید به کلاس‌ها: دکوراتورها می‌توانند برای افزودن متدها یا ویژگی‌های جدید به کلاس‌ها استفاده شوند.

 

  • تزئین کلاس‌ها در پایتون: یک رویکرد قدرتمند برای سفارشی‌سازی رفتار اشیاء

    تزئین کلاس‌ها (Class Decorators) در پایتون، یک مفهوم قدرتمند است که به شما اجازه می‌دهد تا رفتار کلاس‌ها را بدون تغییر در کد اصلی آن‌ها، اصلاح یا گسترش دهید. این کار با استفاده از توابعی به نام دکوراتور انجام می‌شود که قبل از تعریف کلاس قرار می‌گیرند.

    چرا از تزئین کلاس‌ها استفاده می‌کنیم؟
    • سفارشی‌سازی رفتار کلاس‌ها: می‌توانید ویژگی‌های جدیدی به کلاس‌ها اضافه کنید یا رفتار موجود آن‌ها را تغییر دهید.
    • کاهش تکرار کد: با تعریف یک دکوراتور، می‌توانید یک رفتار را به چندین کلاس اعمال کنید و از نوشتن کد تکراری جلوگیری کنید.
    • افزایش خوانایی کد: با تفکیک نگرانی‌ها، کد شما خواناتر و قابل نگهداری‌تر می‌شود.
    نحوه کار تزئین کلاس‌ها

    یک دکوراتور در واقع یک تابع است که کلاسی را به عنوان ورودی می‌گیرد و کلاسی جدید را برمی‌گرداند. این کلاس جدید، کلاس اصلی را با تغییرات دلخواه گسترش می‌دهد.

    Python
    def my_decorator(cls):
        class Wrapper:
            def __init__(self, *args, **kwargs):
                self.wrapped = cls(*args, **kwargs)
    
            # اضافه کردن متد جدید یا تغییر رفتار متدهای موجود
            def new_method(self):
                print("این یک متد جدید است!")
    
        return Wrapper
    
    @my_decorator
    class MyClass:
        def __init__(self, name):
            self.name = name
    
        def greet(self):
            print(f"سلام، من {self.name} هستم.")
    

    در این مثال:

    • my_decorator یک دکوراتور است که کلاس MyClass را تزئین می‌کند.
    • Wrapper یک کلاس داخلی است که کلاس اصلی را در خود قرار می‌دهد.
    • متد new_method یک متد جدید به کلاس MyClass اضافه می‌کند.
    کاربردهای رایج تزئین کلاس‌ها
    • اضافه کردن متدهای استاتیک یا کلاس:
    • اضافه کردن ویژگی‌های جدید:
    • تغییر رفتار متدهای موجود:
    • پیاده‌سازی الگوهای طراحی:
    • مدیریت چرخه عمر اشیاء:
    مثال‌های کاربردی
    • تزئین کلاس‌ها برای ثبت رویدادها:
    • تزئین کلاس‌ها برای اعتبارسنجی داده‌ها:
    • تزئین کلاس‌ها برای ایجاد پروکسی:
    • تزئین کلاس‌ها برای پیاده‌سازی Singleton:
    نکات مهم
    • ترتیب دکوراتورها: ترتیب قرارگیری دکوراتورها مهم است، زیرا دکوراتورها از پایین به بالا اجرا می‌شوند.
    • دکوراتورهای چندگانه: می‌توانید چندین دکوراتور را به یک کلاس اعمال کنید.
    • استفاده از متا کلاس‌ها: برای سفارشی‌سازی بیشتر کلاس‌ها، می‌توانید از متا کلاس‌ها استفاده کنید.
    مزایای استفاده از تزئین کلاس‌ها
    • کاهش پیچیدگی کد: با تفکیک نگرانی‌ها، کد شما تمیزتر و قابل نگهداری‌تر می‌شود.
    • افزایش انعطاف‌پذیری: می‌توانید رفتار کلاس‌ها را بدون تغییر در کد اصلی آن‌ها تغییر دهید.
    • ترویج استفاده مجدد از کد: دکوراتورها می‌توانند برای پیاده‌سازی الگوهای طراحی و ویژگی‌های مشترک استفاده شوند.

    در کل، تزئین کلاس‌ها یک ابزار قدرتمند در پایتون است که به شما اجازه می‌دهد تا کد خود را به صورت بسیار انعطاف‌پذیر و قابل نگهداری طراحی کنید.

     

     

۸. پیاده‌سازی الگوهای طراحی:

  • Singleton: با استفاده از دکوراتورها می‌توانیم الگوی طراحی Singleton را پیاده‌سازی کنیم.
  • Decorator: خود دکوراتورها یک نمونه از الگوی طراحی Decorator هستند.

 

  • پیاده‌سازی الگوهای طراحی در پایتون با استفاده از دکوراتورها

    الگوهای طراحی (Design Patterns) راه حل‌های تکراری برای مشکلات رایج در طراحی نرم‌افزار هستند. این الگوها به ما کمک می‌کنند تا کدهای قابل خواندن‌تر، قابل نگهداری‌تر و انعطاف‌پذیرتری بنویسیم. دکوراتورها در پایتون ابزاری قدرتمندی برای پیاده‌سازی برخی از این الگوها هستند.

    چرا دکوراتورها برای پیاده‌سازی الگوهای طراحی مناسب هستند؟
    • انعطاف‌پذیری: دکوراتورها به شما اجازه می‌دهند بدون تغییر در کد اصلی یک کلاس، رفتار آن را تغییر دهید.
    • کاهش تکرار کد: با تعریف یک دکوراتور، می‌توانید یک رفتار را به چندین کلاس اعمال کنید و از نوشتن کد تکراری جلوگیری کنید.
    • افزایش خوانایی کد: با تفکیک نگرانی‌ها، کد شما خواناتر و قابل نگهداری‌تر می‌شود.

    مثال‌هایی از پیاده‌سازی الگوهای طراحی با دکوراتورها

    ۱. الگوی Decorator (دکوراتور)
    • هدف: اضافه کردن مسئولیت‌های جدید به یک شیء در زمان اجرا بدون تغییر کلاس اصلی آن.
    • پیاده‌سازی:
      Python
      def decorator(cls):
          class Wrapper:
              def __init__(self, *args, **kwargs):
                  self.wrapped = cls(*args, **kwargs)
      
              def __call__(self, *args, **kwargs):
                  # قبل از فراخوانی متد اصلی
                  print("قبل از اجرای متد")
                  result = self.wrapped(*args, **kwargs)
                  # بعد از فراخوانی متد اصلی
                  print("بعد از اجرای متد")
                  return result
          return Wrapper
      
    ۲. الگوی Singleton (تک‌نمونه)
    • هدف: اطمینان از اینکه فقط یک نمونه از یک کلاس وجود دارد.
    • پیاده‌سازی:
      Python
      def singleton(cls):
          instances = {}
          def getinstance(*args, **kwargs):
              if cls not in instances:
                  instances[cls] = cls(*args, **kwargs)
              return instances[cls]
          return getinstance   
      
    ۳. الگوی Strategy (استراتژی)
    • هدف: تعریف یک خانواده از الگوریتم‌ها، کپسوله‌سازی هر یک از آن‌ها و ساخت آن‌ها قابل تعویض.
    • پیاده‌سازی:
      Python
      def strategy(func):
          def wrapper(*args, **kwargs):
              # انتخاب استراتژی مناسب
              strategy = get_strategy()
              return strategy(func, *args, **kwargs)
          return wrapper
      
    مزایای استفاده از دکوراتورها برای پیاده‌سازی الگوهای طراحی
    • انعطاف‌پذیری: دکوراتورها به شما اجازه می‌دهند تا الگوهای طراحی را به صورت پویا و در زمان اجرا اعمال کنید.
    • کاهش پیچیدگی: دکوراتورها می‌توانند پیچیدگی کد را کاهش دهند و آن را قابل خواناتر کنند.
    • توسعه‌پذیری: با اضافه کردن دکوراتورهای جدید، می‌توانید به راحتی رفتار کلاس‌ها را گسترش دهید.
    نکات مهم
    • ترتیب دکوراتورها: ترتیب قرارگیری دکوراتورها مهم است، زیرا دکوراتورها از پایین به بالا اجرا می‌شوند.
    • دکوراتورهای چندگانه: می‌توانید چندین دکوراتور را به یک کلاس اعمال کنید.
    • متا کلاس‌ها: برای سفارشی‌سازی بیشتر کلاس‌ها، می‌توانید از متا کلاس‌ها استفاده کنید.

    در کل، دکوراتورها ابزاری قدرتمند برای پیاده‌سازی الگوهای طراحی در پایتون هستند. با استفاده از دکوراتورها، می‌توانید کدهای خود را به صورت بسیار انعطاف‌پذیر و قابل نگهداری طراحی کنید.

     

مثال عملی: دکوراتور برای ثبت زمان اجرا
Python
import time
from functools import wraps

def timeit(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()   
        print(f"زمان اجرای تابع {func.__name__}: {end_time - start_time:f} ثانیه")
        return result
    return wrapper

@timeit
def my_function():
    # کدهای تابع
    time.sleep(۲)

my_function()

در این مثال، دکوراتور timeit زمان اجرای تابع my_function را محاسبه و چاپ می‌کند.

جمع‌بندی:

دکوراتورها ابزاری قدرتمند و انعطاف‌پذیر در پایتون هستند که به شما اجازه می‌دهند کد خود را تمیزتر، خواناتر و قابل نگهداری‌تر کنید. با درک عمیق از کاربردهای دکوراتورها، می‌توانید از آن‌ها برای حل بسیاری از مشکلات برنامه‌نویسی استفاده کنید.

 

جمع‌بندی:

دکوراتورها ابزاری قدرتمند و انعطاف‌پذیر در پایتون هستند که به شما اجازه می‌دهند بدون تغییر کد اصلی تابع، قابلیت‌های جدیدی به آن اضافه کنید. با استفاده از دکوراتورها، می‌توانید کد خود را تمیزتر، خواناتر و قابل نگهداری‌تر کنید.

 

دکوراتور @app.route در فلاسک

دکوراتور @app.route در فلاسک، یک ابزار قدرتمند برای مرتبط کردن توابع (که به آن‌ها view functions یا توابع نما گفته می‌شود) با URL‌های مختلف در یک برنامه وب است. به عبارت دیگر، این دکوراتور تعیین می‌کند که وقتی کاربری یک آدرس مشخص در مرورگر خود تایپ می‌کند، کدام تابع باید اجرا شود.

ساختار کلی

Python
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello, World!'

در این مثال:

    • app: یک نمونه از کلاس Flask است که برنامه وب ما را نشان می‌دهد.
    • @app.route(‘/’): این دکوراتور به تابع index مرتبط است و می‌گوید که وقتی کاربری آدرس / (صفحه اصلی) را در مرورگر خود تایپ کند، تابع index اجرا می‌شود.
    • def index():: این تابع، محتوایی را که باید به کاربر نمایش داده شود، برمی‌گرداند. در این مثال، یک رشته ساده است.

پارامترهای دکوراتور @app.route

دکوراتور @app.route از چندین پارامتر برای تنظیم رفتار مسیر استفاده می‌کند:

    • rule: یک رشته است که الگوی URL را مشخص می‌کند. به عنوان مثال: /users/<username>.
    • methods: یک لیست از متدهای HTTP مجاز است (مثلاً GET, POST, PUT, DELETE).
    • strict_slashes: یک مقدار بولین است که تعیین می‌کند آیا اسلش پایانی در URL اجباری است یا خیر.
    • subdomain: یک رشته است که زیر دامنه مورد نظر را مشخص می‌کند.

مثال‌های بیشتر

    • مسیر با پارامتر:
      Python
      @app.route('/users/<username>')
      def get_user(username):
          # ...
      

      در این مثال، <username> یک پارامتر مسیر است که مقدار آن در تابع get_user قابل دسترسی است.

    • مسیر با چندین متد HTTP:
      Python
      @app.route('/posts/<post_id>', methods=['GET', 'PUT', 'DELETE'])
      def handle_post(post_id):
          # ...
      

      این مسیر از متدهای GET، PUT و DELETE پشتیبانی می‌کند.

    • مسیر با زیر دامنه:
      Python
      @app.route('/admin', subdomain='api')
      def admin_panel():
          # ...
      

      این مسیر فقط برای زیر دامنه api قابل دسترسی است.

کاربردهای دکوراتور @app.route

    • تعریف مسیرهای مختلف برای صفحات وب: هر صفحه از وب‌سایت شما می‌تواند یک مسیر منحصر به فرد داشته باشد.
    • ایجاد APIهای RESTful: با استفاده از متدهای HTTP مختلف و پارامترهای مسیر، می‌توانید APIهای RESTful قدرتمندی ایجاد کنید.
    • ساخت برنامه‌های وب پویا: با ترکیب دکوراتور @app.route با قالب‌ها و پایگاه داده‌ها، می‌توانید برنامه‌های وب پویایی بسازید.

نکات مهم

    • ترتیب دکوراتورها: ترتیب دکوراتورها مهم نیست.
    • تکرار دکوراتورها: می‌توانید یک تابع را با چندین دکوراتور تزئین کنید.
    • تابع view: تابعی که با دکوراتور @app.route تزئین شده است، باید یک پاسخ HTTP را برگرداند. این پاسخ می‌تواند یک رشته ساده، یک قالب HTML، یک JSON یا هر نوع داده دیگری باشد.

در کل، دکوراتور @app.route یکی از ابزارهای اصلی در فلاسک برای ساخت برنامه‌های وب است. با استفاده از این دکوراتور، می‌توانید به راحتی مسیرهای وب را تعریف کرده و برنامه‌های وب پویا و تعاملی ایجاد کنید.

 

کاربردهای دیگر دکوراتورها در فلاسک

  • مدیریت خطا: دکوراتورهایی وجود دارند که برای مدیریت انواع مختلف خطاها استفاده می‌شوند. مثلاً، می‌توانید یک دکوراتور بنویسید که اگر یک خطا در یک تابع رخ داد، یک پیام خطای سفارشی را نمایش دهد.
  • تأیید هویت: دکوراتورهایی برای تأیید هویت کاربران قبل از دسترسی به برخی از صفحات استفاده می‌شوند.
  • زمان‌بندی: دکوراتورهایی برای زمان‌بندی اجرای توابع استفاده می‌شوند. مثلاً، می‌توانید یک تابع را طوری تنظیم کنید که هر ساعت یک بار اجرا شود.
  • کَش کردن: دکوراتورهایی برای کَش کردن نتایج توابع استفاده می‌شوند تا از محاسبات تکراری جلوگیری شود.
  • تبدیل انواع داده: دکوراتورهایی برای تبدیل انواع داده ورودی و خروجی توابع استفاده می‌شوند.

مزایای استفاده از دکوراتورها

  • کد تمیزتر و خواناتر: با استفاده از دکوراتورها، کد شما ساختارمندتر و قابل فهم‌تر می‌شود.
  • کد تکراری کمتر: دکوراتورها به شما اجازه می‌دهند تا کد تکراری را کاهش دهید و از آن مجدد استفاده کنید.
  • افزایش قابلیت انعطاف‌پذیری: دکوراتورها به شما اجازه می‌دهند تا رفتار توابع را بدون تغییر دادن کد اصلی آن‌ها تغییر دهید.

جمع‌بندی

دکوراتورها ابزاری قدرتمند در فلاسک هستند که به شما اجازه می‌دهند تا کد خود را بهینه سازی کرده و قابلیت‌های جدیدی به آن اضافه کنید. با درک نحوه کار دکوراتورها، می‌توانید برنامه‌های وب فلاسک خود را با کیفیت بالاتر و کارایی بیشتری توسعه دهید.

۵/۵ ( ۱ امتیاز )
نمایش بیشتر

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا