شعار زيفيرنت

فهم إغلاقات بايثون: الغوص العميق في البرمجة الوظيفية

التاريخ:

المُقدّمة

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

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

جدول المحتويات

ما هي عمليات الإغلاق في بايثون؟

عمليات الإغلاق في بايثون هي وظائف تتذكر البيئة التي تم إنشاؤها فيها. يمكنهم الوصول إلى المتغيرات من النطاق المرفق الخاص بهم. 

على سبيل المثال، ضع في اعتبارك مقتطف الشفرة هذا:

رمز:

def outer_function(message):

    def inner_function():

        print(message)

    

    return inner_function

my_func = outer_function("Hello, World!")

my_func()

في هذا الكود، تعد `الوظيفة_الداخلية` بمثابة إغلاق يتذكر متغير `الرسالة` من outer_function. عندما يتم استدعاء `my_func`، فإنه يطبع "Hello, World!".

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

كيف تعمل عمليات الإغلاق في بايثون؟

وظائف متداخلة

في بايثون، يمكننا تعريف دالة داخل دالة أخرى. يُعرف هذا بالوظيفة المتداخلة.

رمز:

def outer_function():

    x = 10

    def inner_function():

        print(x)

    inner_function()

outer_function()

الوصول إلى المتغيرات من الوظائف الخارجية

يمكن للوظائف الداخلية الوصول إلى المتغيرات من وظائفها الخارجية. هذا ممكن بسبب عمليات الإغلاق.

رمز:

def outer_function():

    x = 10

    def inner_function():

        print(x)

    return inner_function

my_func = outer_function()

my_func()

إرجاع الوظائف من الوظائف

في بايثون، يمكن للوظائف إرجاع وظائف أخرى. هذه ميزة قوية للبرمجة الوظيفية.

رمز:

def outer_function(msg):

    def inner_function():

        print(msg)

    return inner_function

my_func = outer_function("Hello, World!")

my_func()

من خلال فهم الوظائف المتداخلة، والوصول إلى المتغيرات من الوظائف الخارجية، وإرجاع الوظائف من الوظائف، يمكنك الاستفادة من قوة عمليات الإغلاق في بايثون.

حالات الاستخدام اليومي لإغلاقات بايثون

وظائف رد الاتصال

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

رمز:

def callback_function():

    print("Callback function called")

def main_function(callback):

    print("Main function executing")

    callback()

main_function(callback_function)

ديكور

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

رمز:

def my_decorator(func):

    def wrapper():

        print("Something is happening before the function is called.")

        func()

        print("Something is happening after the function is called.")

    return wrapper

@my_decorator

def say_hello():

    print("Hello!")

say_hello()

المذكرات

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

رمز:

def memoize(func):

    cache = {}

    def wrapper(n):

        if n not in cache:

            cache[n] = func(n)

        return cache[n]

    return wrapper

@memoize

def fibonacci(n):

    if n <= 1:

        return n

    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))

التعامل مع الحدث

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

رمز:

def event_handler(event):

    print(f"Event {event} occurred")

def simulate_event(event, handler):

    print("Simulating event...")

    handler(event)

simulate_event("button_click", event_handler)

تنفيذ إغلاق بايثون

إنشاء الإغلاق

لإنشاء إغلاق في بايثون، يجب عليك تحديد دالة متداخلة داخل دالة أخرى. يجب أن تشير الدالة الداخلية إلى متغيرات من الدالة الخارجية لتكوين إغلاق. لنلقي نظرة على مثال:

رمز:

def outer_function(outer_variable):

    def inner_function(inner_variable):

        return outer_variable + inner_variable

    return inner_function

closure = outer_function(5)

print(closure(3))

الإخراج:

8

في مقتطف الرمز هذا، تعرض `الوظيفة_الخارجية` `الوظيفة_الداخلية`، والتي تتذكر قيمة `المتغير_الخارجي` حتى بعد انتهاء تنفيذ `الوظيفة_الخارجية`. هذا هو جوهر الإغلاق.

استخدام عمليات الإغلاق في أمثلة العالم الحقيقي

تُستخدم عمليات الإغلاق بشكل شائع في آليات التعامل مع الأحداث ووظائف رد الاتصال والديكورات في بايثون. دعونا نرى مثالاً عمليًا لاستخدام عمليات الإغلاق لإنشاء آلة حاسبة بسيطة:

رمز:

def calculator(operator):

    def calculate(num1, num2):

        if operator == '+':

            return num1 + num2

        elif operator == '-':

            return num1 - num2

        elif operator == '*':

            return num1 * num2

        elif operator == '/':

            return num1 / num2

    return calculate

addition = calculator('+')

print(addition(5, 3))

الإخراج:

8

في هذا المثال، يسمح لنا إغلاق `الحاسبة' بإنشاء وظائف حاسبة مختلفة بناءً على عامل التشغيل الذي تم تمريره إليها.

التعامل مع المتغيرات المتغيرة والغير قابلة للتغيير

عند التعامل مع عمليات الإغلاق، من الضروري فهم كيفية تعامل بايثون مع المتغيرات القابلة للتغيير وغير القابلة للتغيير. يتم تمرير المتغيرات غير القابلة للتغيير مثل الأعداد الصحيحة والسلاسل حسب القيمة، بينما يتم تمرير المتغيرات القابلة للتغيير مثل القوائم والقواميس حسب المرجع. ولنوضح ذلك بمثال:

رمز:

def outer_function():

    count = 0

    def inner_function():

        nonlocal count

        count += 1

        return count

    return inner_function

counter = outer_function()

print(counter())  # Output: 

print(counter())  # Output: 12

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

وفي الختام

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

بقعة_صورة

أحدث المعلومات الاستخباراتية

بقعة_صورة