0Pricing
Coding Interview Prep · درس

الدوال والإغلاقات وLambda

عرّف دوال مساعدة قابلة لإعادة الاستخدام، واستخدم الوسائط الافتراضية، وطبّق تعبيرات lambda على الفرز والأنماط الوظيفية في مسائل المقابلات

الدوال والإغلاقات وLambda درس مجاني في Coding Interview Prep على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Coding Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.

تعريف الدوال في Python

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

def is_palindrome(s: str) -> bool:
    '''Return True if s reads the same forwards and backwards.'''
    s = s.lower()
    return s == s[::-1]

print(is_palindrome('Racecar'))  # True
print(is_palindrome('hello'))    # False

# Functions as values
checks = [is_palindrome]
print(checks[0]('level'))  # True

المعاملات الافتراضية والمسماة

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

# WRONG: shared mutable default
def bad_append(val, lst=[]):
    lst.append(val)
    return lst

print(bad_append(1))  # [1]
print(bad_append(2))  # [1, 2]  surprise!

# CORRECT: use None sentinel
def good_append(val, lst=None):
    if lst is None:
        lst = []
    lst.append(val)
    return lst

print(good_append(1))  # [1]
print(good_append(2))  # [2]

*args و**kwargs

تجمع *args المعاملات الموضعية الإضافية في tuple، بينما تجمع **kwargs المعاملات الإضافية المسماة في dict. كما تفك * تسلسلًا عند استدعاء دالة.

def total(*args):
    return sum(args)

print(total(1, 2, 3))     # 6
print(total(1, 2, 3, 4))  # 10

# Unpack a list as positional args
point = [3, 7]
print(max(*point))   # 7

# **kwargs
def greet(**kwargs):
    name = kwargs.get('name', 'World')
    return f'Hello, {name}!'

print(greet(name='Alice'))  # Hello, Alice!

تعبيرات Lambda

إنّ lambda دالة صغيرة في سطر واحد: lambda params: expression. وهي مثالية كـ key سريع في sorted أو max. أما ما هو أكبر من ذلك، فتكون دالة def ذات اسم أوضح قراءةً.

# Lambda as sort key
pairs = [(1, 3), (2, 1), (3, 2)]
sorted_by_second = sorted(pairs, key=lambda p: p[1])
print(sorted_by_second)  # [(2,1),(3,2),(1,3)]

# Lambda with map
double = list(map(lambda n: n * 2, [1, 2, 3]))
print(double)  # [2, 4, 6]

# Named function is clearer for complex logic
def sort_key(p):
    return (p[1], -p[0])  # secondary sort
print(sorted(pairs, key=sort_key))

الدوال المتداخلة وClosures

إنّ closure دالة تتذكر المتغيرات من الدالة المحيطة بها. عرّفوا دالة مساعدة داخل دالة أخرى، وستتمكن من استخدام متغيرات الدالة الخارجية، وهو أمر مفيد في DFS.

def make_counter(start=0):
    count = [start]  # list to allow mutation
    def increment():
        count[0] += 1
        return count[0]
    return increment

counter = make_counter()
print(counter())  # 1
print(counter())  # 2

# Alternative: nonlocal keyword
def make_counter2():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

Closures في DFS العودي

من الأنماط الشائعة تعريف دالة مساعدة باسم dfs داخل الدالة الرئيسية، والسماح لها بجمع النتائج في متغير خارجي. وتكون الدالة الداخلية closure على ذلك النطاق.

def max_depth(root):
    '''Closure pattern for tree DFS.'''
    max_d = [0]  # mutable container for closure

    def dfs(node, depth):
        if node is None:
            return
        max_d[0] = max(max_d[0], depth)
        dfs(node.left, depth + 1)
        dfs(node.right, depth + 1)

    dfs(root, 1)
    return max_d[0]
# This pattern avoids a class or global state.

functools.lru_cache للحفظ المؤقت

يتذكر lru_cache (أو @cache في الإصدار 3.9 فما بعده) نتائج الدالة وفقًا لمعاملاتها، فيحوّل Fibonacci الساذج من O(2^n) إلى O(n). ويجب أن تكون المعاملات قابلة للتجزئة، لذا استخدموا Tuples.

from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n <= 1:
        return n
    return fib(n - 1) + fib(n - 2)

print(fib(40))   # 102334155  fast!
print(fib.cache_info())  # hits, misses, size

الدوال من الرتبة العليا

تأخذ الدالة من الرتبة العليا دالةً أو تُرجعها. وتندرج sorted وmap وfilter جميعًا ضمن ذلك. وتتيح لكم كتابة دوالكم الخاصة تجريد الأنماط المتكررة. يوضّح الكود التركيب.

def apply_twice(f, x):
    return f(f(x))

print(apply_twice(lambda n: n * 2, 3))  # 12  (3*2*2)

# Composing transformations
def compose(f, g):
    return lambda x: f(g(x))

double = lambda n: n * 2
add_one = lambda n: n + 1
double_then_add = compose(add_one, double)
print(double_then_add(5))  # 11  ((5*2)+1)

الاستدعاء الذاتي مع الدوال المساعدة

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

def flatten(nested):
    '''Flatten an arbitrarily nested list.'''
    result = []

    def _flatten(lst):
        for item in lst:
            if isinstance(item, list):
                _flatten(item)
            else:
                result.append(item)

    _flatten(nested)
    return result

print(flatten([1, [2, [3, 4], 5], 6]))
# [1, 2, 3, 4, 5, 6]

الدوال الجزئية باستخدام functools.partial

تملأ functools.partial بعض المعاملات مسبقًا وتُرجع callable جديدة. وهي مفيدة عندما تتطلب واجهة برمجية دالة بلا معاملات، بينما تحتاجون إلى تثبيت قيمة معامل واحد.

from functools import partial

def power(base, exp):
    return base ** exp

square = partial(power, exp=2)
cube   = partial(power, exp=3)

print(square(5))   # 25
print(cube(3))     # 27
print(list(map(square, [1, 2, 3, 4])))  # [1, 4, 9, 16]

Lambda للمقارنات المخصصة

أزالت Python 3 المقارنات ذات المعاملين، لكن cmp_to_key يعيدها للترتيبات المعقدة، مثل ترتيب الأعداد بحيث يكون ناتج وصلها أكبر ما يمكن. راجعوا الكود.

from functools import cmp_to_key

def largest_number(nums):
    def compare(a, b):
        if a + b > b + a: return -1
        if a + b < b + a: return 1
        return 0
    strs = list(map(str, nums))
    strs.sort(key=cmp_to_key(compare))
    result = ''.join(strs)
    return '0' if result[0] == '0' else result

print(largest_number([3, 30, 34, 5, 9]))  # '9534330'

تحقق سريع

تحقق سريع — حان الوقت لإظهار ما تعلمتموه عن الدوال وclosures وlambdas. خذوا نفسًا وابدؤوا. 🚀

مراجعة الدرس

مراجعة: لا تستخدموا القيم الافتراضية القابلة للتغيير أبدًا (استخدموا None)، وتتيح closures للدوال المساعدة الداخلية الوصول إلى المتغيرات الخارجية في DFS، بينما تدعم أدوات functools مثل lru_cache الحلول السريعة.

الأسئلة الشائعة

هل درس «الدوال والإغلاقات وLambda» مجاني؟

نعم — نص درس «الدوال والإغلاقات وLambda» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Coding Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.

ماذا ستتعلم في «الدوال والإغلاقات وLambda»؟

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

هل أحتاج إلى خبرة سابقة لأبدأ Coding Interview Prep؟

لا تُشترط خبرة سابقة. Coding Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «الدوال والإغلاقات وLambda»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Coding Interview Prep هذا؟

نعم. كل درس في Coding Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. القوائم والصفوف والتقطيع
  2. القواميس والمجموعات في Python
  3. الاختصارات والدوال المضمّنة
  4. الدوال والإغلاقات وLambda
← العودة إلى Coding Interview Prep