شرح (مع أمثلة وحالات استخدام)

تعتبر أدوات تزيين بايثون بناء مفيد بشكل لا يصدق في بايثون. باستخدام أدوات الزخرفة في Python ، يمكننا تعديل سلوك دالة عن طريق لفها داخل دالة أخرى. يمكّننا المصممون من كتابة كود أنظف ومشاركة الوظائف. هذه المقالة عبارة عن برنامج تعليمي ليس فقط حول كيفية استخدام المصممين ولكن كيفية إنشائهم.

المعرفة المطلوبة

يتطلب موضوع الديكور في بايثون بعض المعرفة الأساسية. أدناه ، قمت بإدراج بعض المفاهيم التي يجب أن تكون على دراية بها بالفعل لفهم هذا البرنامج التعليمي. لقد قمت أيضًا بربط الموارد حيث يمكنك تحسين المفاهيم إذا لزم الأمر.

بايثون الأساسية

هذا الموضوع هو موضوع متوسط ​​/ متقدم. نتيجة لذلك ، قبل محاولة التعلم ، يجب أن تكون على دراية بأساسيات بايثون ، مثل أنواع البيانات والوظائف والكائنات والفئات.

يجب أن تفهم أيضًا بعض المفاهيم الموجهة للكائنات مثل الحاصل ، والمحددون ، والمنشئون. إذا لم تكن معتادًا على لغة برمجة Python ، فإليك بعض الموارد للبدء.

وظائف المواطنين من الدرجة الأولى

بالإضافة إلى لغة بايثون الأساسية ، يجب أن تكون على دراية بهذا المفهوم الأكثر تقدمًا في بايثون. الوظائف ، وكل شيء آخر في Python ، هي كائنات مثل int أو string. لأنها كائنات ، يمكنك القيام ببعض الأشياء بها ، وهي:

  • يمكنك تمرير دالة كوسيطة إلى دالة أخرى بنفس الطريقة التي تمرر بها سلسلة نصية أو int كوسيطة دالة.
  • يمكن أيضًا إرجاع الوظائف بواسطة دوال أخرى مثل إرجاع سلسلة نصية أخرى أو قيم int.
  • يمكن تخزين الوظائف في المتغيرات

في الواقع ، الاختلاف الوحيد بين الكائنات الوظيفية والكائنات الأخرى هو أن الكائنات الوظيفية تحتوي على الطريقة السحرية __call __ ().

نأمل ، في هذه المرحلة ، أن تكون مرتاحًا للمعرفة المطلوبة مسبقًا. يمكننا البدء في مناقشة الموضوع الرئيسي.

ما هو مصمم بايثون؟

مصمم بايثون هو ببساطة وظيفة تأخذ وظيفة كوسيطة وتعيد نسخة معدلة من الوظيفة التي تم تمريرها. وبعبارة أخرى ، فإن الوظيفة foo هي مصمم إذا أخذت ، كوسيطة ، شريط الوظائف وإرجاع دالة أخرى baz.

وظيفة baz هي تعديل للشريط بمعنى أنه يوجد استدعاء لشريط الوظائف داخل جسم baz. ومع ذلك ، قبل المكالمة إلى الحانة وبعدها ، يستطيع باز فعل أي شيء. كان ذلك من الفم. إليك بعض التعليمات البرمجية لتوضيح الموقف:

# Foo is a decorator, it takes in another function, bar as an argument
def foo(bar):

    # Here we create baz, a modified version of bar
    # baz will call bar but can do anything before and after the function call
    def baz():

        # Before calling bar, we print something
        print("Something")

        # Then we run bar by making a function call
        bar()

        # Then we print something else after running bar
        print("Something else")

    # Lastly, foo returns baz, a modified version of bar
    return baz

كيف تصنع ديكور في بايثون؟

لتوضيح كيفية إنشاء المصممين واستخدامهم في بايثون ، سأقوم بتوضيح ذلك بمثال بسيط. في هذا المثال ، سننشئ وظيفة تزيين المسجل والتي ستسجل اسم الوظيفة التي تقوم بتزيينها في كل مرة يتم فيها تشغيل هذه الوظيفة.

  كيفية الحصول على حالة الرسائل الإلكترونية المرسلة والمرئية في Gmail

للبدء ، أنشأنا وظيفة الديكور. يأخذ الديكور في func كحجة. func هي الوظيفة التي نقوم بتزيينها.

def create_logger(func):
    # The function body goes here

داخل وظيفة الديكور ، سنقوم بإنشاء وظيفتنا المعدلة التي ستسجل اسم func قبل تشغيل func.

# Inside create_logger
def modified_func():
    print("Calling: ", func.__name__)
    func()

بعد ذلك ، ستعيد وظيفة create_logger الوظيفة المعدلة. نتيجة لذلك ، ستبدو وظيفة create_logger بأكملها كما يلي:

def create_logger(func):
    def modified_func():
        print("Calling: ", func.__name__)
        func()

    return modified_function

لقد انتهينا من إنشاء المصمم. تعتبر وظيفة create_logger مثالًا بسيطًا لوظيفة الزخرفة. يأخذ في func ، وهي الوظيفة التي نقوم بتزيينها ، وإرجاع وظيفة أخرى ، modified_func. تم تعديل اسم func أولاً قبل تشغيل func.

كيفية استخدام أدوات الديكور في لغة بايثون

لاستخدام مصمم الديكور الخاص بنا ، نستخدم الصيغة @ كما يلي:

@create_logger
def say_hello():
    print("Hello, World!")

الآن يمكننا استدعاء say_hello () في البرنامج النصي الخاص بنا ، ويجب أن يكون الناتج هو النص التالي:

Calling:  say_hello
"Hello, World"

ولكن ما الذي يفعلهcreate_logger؟ حسنًا ، إنه تطبيق الديكور على وظيفة say_hello الخاصة بنا. لفهم ما يتم فعله بشكل أفضل ، فإن الكود الموجود أسفل هذه الفقرة مباشرة سيحقق نفس النتيجة مثل وضعcreate_logger قبل say_hello.

def say_hello():
    print("Hello, World!")

say_hello = create_logger(say_hello)

بمعنى آخر ، تتمثل إحدى طرق استخدام أدوات الزخرفة في Python في استدعاء المصمم الذي يمر في الوظيفة بشكل صريح كما فعلنا في الكود أعلاه. الطريقة الأخرى والأكثر إيجازًا هي استخدام بناء الجملة @.

في هذا القسم ، تناولنا كيفية إنشاء أدوات تزيين بايثون.

أمثلة أكثر تعقيدًا بعض الشيء

المثال أعلاه كان حالة بسيطة. هناك أمثلة أكثر تعقيدًا إلى حد ما مثل عندما تأخذ الوظيفة التي نقوم بتزيينها الحجج. هناك موقف أكثر تعقيدًا عندما تريد تزيين فصل كامل. سأقوم بتغطية كلتا الحالتين هنا.

عندما تأخذ الوظيفة في الحجج

عندما تأخذ الوظيفة التي تقوم بتزيينها في الوسائط ، يجب أن تتلقى الوظيفة المعدلة الوسائط وتمريرها عندما تقوم في النهاية باستدعاء الوظيفة غير المعدلة. إذا كان هذا يبدو محيرًا ، اسمحوا لي أن أشرح بعبارات foo-bar.

تذكر أن foo هي وظيفة الديكور ، والبار هو الوظيفة التي نقوم بتزيينها والباز هو الشريط المزين. في هذه الحالة ، سيأخذ Bar الوسائط ويمررها إلى baz أثناء استدعاء baz. فيما يلي مثال على رمز لترسيخ المفهوم:

def foo(bar):
    def baz(*args, **kwargs):
        # You can do something here
        ___
        # Then we make the call to bar, passing in args and kwargs
        bar(*args, **kwargs)
        # You can also do something here
        ___

    return baz

إذا كانت * args و ** kwargs تبدو غير مألوفة ؛ هم مجرد مؤشرات إلى الحجج الموضعية والكلمات الرئيسية ، على التوالي.

من المهم ملاحظة أن baz لديه حق الوصول إلى الوسائط وبالتالي يمكنه إجراء بعض التحقق من صحة الوسائط قبل استدعاء bar.

على سبيل المثال ، إذا كان لدينا وظيفة تزيين ، تأكد من أن الوسيطة التي تم تمريرها إلى وظيفة تقوم بتزيينها هي سلسلة ؛ سوف ننفذها على النحو التالي:

def ensure_string(func):
    def decorated_func(text):
        if type(text) is not str:
             raise TypeError('argument to ' + func.__name__ + ' must be a string.')
        else:
             func(text)

    return decorated_func

يمكننا تزيين وظيفة say_hello مثل:

@ensure_string
def say_hello(name):
    print('Hello', name)

ثم يمكننا اختبار الكود باستخدام هذا:

say_hello('John') # Should run just fine
say_hello(3) # Should throw an exception

ويجب أن ينتج الناتج التالي:

Hello John
Traceback (most recent call last):
   File "/home/anesu/Documents/python-tutorial/./decorators.py", line 20, in <module> say hello(3) # should throw an exception
   File "/home/anesu/Documents/python-tu$ ./decorators.pytorial/./decorators.py", line 7, in decorated_func raise TypeError('argument to + func._name_ + must be a string.')
TypeError: argument to say hello must be a string. $0

كما هو متوقع ، تمكن البرنامج النصي من طباعة “Hello John” لأن “John” عبارة عن سلسلة. لقد طرح استثناءً عند محاولة طباعة “Hello 3” لأن الرقم “3” لم يكن سلسلة. يمكن استخدام أداة الديكور warranty_string للتحقق من صحة وسيطات أي دالة تتطلب سلسلة.

  كيفية تمكين المجلد الآمن على هواتف سامسونج

تزيين الفصل

بالإضافة إلى وظائف التزيين فقط ، يمكننا أيضًا تزيين الفصول الدراسية. عند إضافة مصمم إلى فصل دراسي ، فإن الطريقة المزخرفة تحل محل طريقة البادئ / المُنشئ للفصل (__ init__).

بالعودة إلى foo-bar ، لنفترض أن foo هو مصمم الديكور لدينا والبار هو الفصل الذي نقوم بتزيينه ، ثم سيقوم foo بتزيين Bar .__ init__. سيكون هذا مفيدًا إذا أردنا القيام بأي شيء قبل إنشاء كائنات من نوع شريط.

هذا يعني أن الكود التالي

def foo(func):
    def new_func(*args, **kwargs):
        print('Doing some stuff before instantiation')
        func(*args, **kwargs)

    return new_func

@foo
class Bar:
    def __init__(self):
        print("In initiator")

يعادل

def foo(func):
    def new_func(*args, **kwargs):
        print('Doing some stuff before instantiation')
        func(*args, **kwargs)

    return new_func

class Bar:
    def __init__(self):
        print("In initiator")


Bar.__init__ = foo(Bar.__init__)

في الواقع ، يجب أن يمنحك إنشاء كائن من فئة Bar ، المعرّف باستخدام أي من الطريقتين ، نفس الإخراج:

Doing some stuff before instantiation
In initiator

مثال للديكور في بايثون

بينما يمكنك تحديد الديكور الخاص بك ، إلا أن هناك البعض منها مدمج بالفعل في Python. فيما يلي بعض أدوات الديكور الشائعة التي قد تصادفها في Python:

تضمين التغريدة

يتم استخدام الطريقة الثابتة في الفصل للإشارة إلى أن الطريقة التي يتم تزيينها بها هي طريقة ثابتة. الطرق الثابتة هي طرق يمكن تشغيلها دون الحاجة إلى إنشاء مثيل للفئة. في مثال الكود التالي ، قمنا بإنشاء فئة Dog باستخدام طريقة ثابتة لحاء.

class Dog:
    @staticmethod
    def bark():
        print('Woof, woof!')

الآن يمكن الوصول إلى طريقة اللحاء على النحو التالي:

Dog.bark()

وسيؤدي تشغيل الكود إلى إنتاج المخرجات التالية:

Woof, woof!

كما ذكرت في القسم الخاص بكيفية استخدام أدوات الديكور ، يمكن استخدام المصممين بطريقتين. يعتبر بناء الجملة @ أكثر إيجازًا كونه واحدًا من الاثنين. الطريقة الأخرى هي استدعاء وظيفة الديكور ، وتمرير الوظيفة التي نريد تزيينها كحجة. بمعنى أن الكود أعلاه يحقق نفس الشيء مثل الكود أدناه:

class Dog:
    def bark():
        print('Woof, woof!')

Dog.bark = staticmethod(Dog.bark)

ولا يزال بإمكاننا استخدام طريقة اللحاء بنفس الطريقة

Dog.bark()

وسوف ينتج نفس الناتج

Woof, woof!

كما ترى ، الطريقة الأولى هي أنظف ومن الواضح أن الوظيفة هي وظيفة ثابتة قبل أن تبدأ حتى في قراءة الكود. نتيجة لذلك ، بالنسبة للأمثلة المتبقية ، سأستخدم الطريقة الأولى. لكن تذكر فقط أن الطريقة الثانية هي بديل.

تضمين التغريدة

يستخدم هذا المصمم للإشارة إلى أن الطريقة التي يتم تزيينها بها هي طريقة الفصل. تشبه طرق الفئة الطرق الثابتة من حيث أنها لا تتطلب إنشاء مثيل للفئة قبل أن يتم استدعاؤها.

  كيفية الحصول على شهادة أخصائي دعم تكنولوجيا المعلومات من Google

ومع ذلك ، فإن الاختلاف الرئيسي هو أن طرق الفئات لها حق الوصول إلى سمات الفئة بينما لا تفعل الطرق الثابتة. هذا لأن Python تمرر الفئة تلقائيًا كأول وسيط إلى طريقة class عندما يتم استدعاؤها. لإنشاء طريقة فصل في بايثون ، يمكننا استخدام مصمم طريقة الفصل.

class Dog:
    @classmethod
    def what_are_you(cls):
        print("I am a " + cls.__name__ + "!")

لتشغيل الكود ، نقوم ببساطة باستدعاء الطريقة دون إنشاء مثيل للفئة:

Dog.what_are_you()

والمخرج هو:

I am a Dog!

@ملكية

يتم استخدام مصمم الديكور لتسمية طريقة ما كمحدد للخصائص. بالعودة إلى مثال الكلب الخاص بنا ، لنقم بإنشاء طريقة لاسترداد اسم الكلب.

class Dog:
    # Creating a constructor method that takes in the dog's name
    def __init__(self, name):

         # Creating a private property name
         # The double underscores make the attribute private
         self.__name = name

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

الآن يمكننا الوصول إلى اسم الكلب مثل خاصية عادية ،

# Creating an instance of the class
foo = Dog('foo')

# Accessing the name property
print("The dog's name is:", foo.name)

وستكون نتيجة تشغيل الكود

The dog's name is: foo

@ property.setter

تُستخدم أداة الديكور property.setter لإنشاء طريقة ضبط لخصائصنا. لاستخدام مصمم الديكور @ property.setter ، يمكنك استبدال الخاصية باسم الخاصية ، فأنت تقوم بإنشاء أداة ضبط لـ. على سبيل المثال ، إذا كنت تقوم بإنشاء أداة ضبط لطريقة الخاصية foo ، فسيكون مصمم الديكور الخاص بك هو @ foo.setter. هنا مثال الكلب لتوضيح:

class Dog:
    # Creating a constructor method that takes in the dog's name
    def __init__(self, name):

         # Creating a private property name
         # The double underscores make the attribute private
         self.__name = name

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

    # Creating a setter for our name property
    @name.setter
    def name(self, new_name):
        self.__name = new_name

لاختبار أداة الضبط ، يمكننا استخدام الكود التالي:

# Creating a new dog
foo = Dog('foo')

# Changing the dog's name
foo.name="bar"

# Printing the dog's name to the screen
print("The dog's new name is:", foo.name)

سيؤدي تشغيل الكود إلى إنتاج المخرجات التالية:

The dogs's new name is: bar

أهمية الديكور في لغة بايثون

الآن بعد أن غطينا ماهية الديكور ، ورأيت بعض الأمثلة على المصممين ، يمكننا مناقشة سبب أهمية المصممين في بايثون. الديكور مهم لعدة أسباب. أدرجت بعضها أدناه:

  • أنها تتيح إعادة استخدام الكود: في مثال التسجيل الموضح أعلاه ، يمكننا استخدامcreate_logger في أي وظيفة نريدها. يتيح لنا ذلك إضافة وظائف التسجيل إلى جميع وظائفنا دون كتابتها يدويًا لكل وظيفة.
  • إنها تسمح لك بكتابة رمز معياري: مرة أخرى ، بالرجوع إلى مثال التسجيل ، مع الزخارف ، يمكنك فصل الوظيفة الأساسية ، في هذه الحالة say_hello عن الوظائف الأخرى التي تحتاجها ، في هذه الحالة ، التسجيل.
  • أنها تعزز الأطر والمكتبات: يتم استخدام المصممين على نطاق واسع في أطر عمل Python والمكتبات لتوفير وظائف إضافية. على سبيل المثال ، في أطر الويب مثل Flask أو Django ، تُستخدم أدوات الزخرفة لتحديد المسارات أو التعامل مع المصادقة أو تطبيق البرامج الوسيطة على طرق عرض محددة.

الكلمات الأخيرة

المصممون مفيدون بشكل لا يصدق. يمكنك استخدامها لتوسيع الوظائف دون تغيير وظائفها. يكون هذا مفيدًا عندما تريد ضبط وقت أداء الوظائف ، أو تسجيل وقت استدعاء دالة ، أو التحقق من صحة الوسائط قبل استدعاء دالة ، أو التحقق من الأذونات قبل تشغيل الوظيفة. بمجرد فهمك لمصممي الديكور ، ستتمكن من كتابة التعليمات البرمجية بطريقة أنظف.

بعد ذلك ، قد ترغب في قراءة مقالاتنا حول tuples واستخدام cURL في Python.