counterexample

فعلن فقط برنامه نویسی

counterexample

فعلن فقط برنامه نویسی

جمعه, ۸ آذر ۱۳۹۸، ۰۵:۰۰ ب.ظ

۰

دکوراتور در پایتون

جمعه, ۸ آذر ۱۳۹۸، ۰۵:۰۰ ب.ظ

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

در ادامه مطلب یه مثال ازش میبینیم: 

فرض کنید که برای متد post یه وبسرویس یه تابع نوشتیم، این وبسرویس قراره نام کاربری و کلمه عبور کاربر رو دریافت کنه و کااربر رو داخل دیتابیس ثبت کنه.. تابعمون یه همچین شکلی خواهد داشت:

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

 

کد زیر را در نظر بگیرید:

 def post(self, request, *args, **kwargs):
        a_user = User.objects.create(
            userName=request.data["username"],
            pass=request.data["password"]
        )
        responseBody=UserSerializer(a_user).data
        responseBody["message"]="[Success]"
        return Response(
            data=responseBody,
            status=status.HTTP_201_CREATED
        )

 

 

خب اما بعدش متوجه میشیم که ما برای این کار اصلا اطلاعات وارد شده از سمت کاربر رو بررسی نکردیم! مثلا حتی چک نکردیم که طرف ممکنه فیلد خالی بفرسته! برای اینکه این قابلیتو به تابعمون اضافه کنیم یه دکوراتور واسه این کار مینویسیم به صورت زیر:
 
def validate_request_data(func):
    def decorated(*args, **kwargs):
        # args[0] == GenericView Object
        userName = args[0].request.data.get("username", "")
        passWord = args[0].request.data.get("password", "")
        if not passWord or not userName:
            return Response(
                data={
                    "message": "[Unsuccessful] Both password and userName are required to add a use"
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        return func(*args, **kwargs)
    return decorated

 

شاید ظاهرش یه کم براتون عجیب باشه.. توی دکوراتور اول از همه اسمش رو مینویسیم (validate_request_data) و ورودی اون یه تابع هست. همون تابعی که قراره بیاد داخلش و فیلدهاش چک بشه.. پس ما اون تابعی که برای متد پست نوشتیم قراره ورودی دکوراتورvalidate_request_data باشه.
 
در ادامه همه دکوراتور ها این بخش رو دارن که با نام های decorated یا wrapper یا هر اسمی که بخواید میتونید تعریفش کنید ورودیهاش هم همون ورودیهای تابع اولیه مون هستن که آوردیم داخل دکوراتور. در ادامه ورودیها (فیلد هایی که کاربر وارد کرده بود) رو چک میکنیم که اگه یه وقت یکیشون خالی بود بگیم خروجی متد پست مون پیغام "نا موفق" باشه. و اگه هیچکدوم فیلد ها خالی نبود خود تابعی که میخواستیم پیغام موفقیت آمیز نشون بده رو صدا میزنیم همون طور که تو کد بالا هم نوشتیم:
 
return func(*args, **kwargs)

 

 
و حالا در آخر برای اینکه دکوراتور رو به تابعمون وصل کنیم به همین راحتی بالای تابعی که تعریف کردیم اسم دکوراتورمونو میاریم.
ینی این شکلی میشه تابعمون:
 
  @validate_request_data
    def post(self, request, *args, **kwargs):
        a_product = Product.objects.create(
            productId=request.data["productId"],
            userId=request.data["userId"]
        )
        resBody=ProductSerializer(a_product).data
        resBody["message"]="[Success]"
        return Response(
            data=resBody,
            status=status.HTTP_201_CREATED
        )

 

 
با این کار هر بار که تابع post صدا زده بشه، مثل اینه که این خط رو صدا زدیم:
validate_request_data(post)

یعنی یکبار فیلدهاشو چک میکنه و درنهایت خود تابع رو صدا میزنه :)

تمام.
 
 

 

موافقین ۰ مخالفین ۰ ۹۸/۰۹/۰۸
counter example

نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">