أين يعيش الاسم
نطاق الاسم هو الجزء من البرنامج الذي يمكن استخدامه فيه. الاسم المُنشأ داخل دالة محلي: يوجد فقط أثناء عمل الدالة ولا يُرى خارجها. أما الاسم المُنشأ في المستوى الأعلى للملف فهو عام: تستطيع الدوال قراءته. عندما تصادف Python اسمًا تبحث أولًا في الدالة، ثم في أي دالة محيطة، ثم في الملف، ثم في الأسماء المدمجة.
rate = 0.001 # global: defined outside any function
def fee(notional):
minimum = 1.0 # local: exists only during the call
return max(minimum, notional * rate)
print(fee(36850.0)) # 36.85
# print(minimum) # would raise NameError: minimum is not definedالإسناد ينشئ اسمًا محليًا
قراءة اسم عام من داخل دالة أمر لا بأس به. لكن الإسناد إلى اسم داخل دالة ينشئ اسمًا محليًا جديدًا حتى لو وُجد اسم عام بالاسم نفسه: يبقى العام كما هو. هذا يحمي بياناتك، وهو أيضًا سبب أن تغيير حالة عامة من داخل دالة يتطلب كلمات إضافية (global) نادرًا ما تحتاجها. مرّر القيم كوسائط وأعد النتائج بـreturn.
# Assigning inside a function makes a new local name
balance = 1000
def deposit(amount):
balance = amount # a different, local balance
return balance
print(deposit(50)) # 50
print(balance) # 1000 (the global one is unchanged)دوال تصنع دوال
يمكن لدالة أن تعرّف دالة أخرى داخلها وتُرجعها بـreturn. تحتفظ الدالة الداخلية بإمكانية الوصول إلى متغيرات الخارجية حتى بعد انتهاء الخارجية. هذه الحزمة المكوّنة من دالة والقيم التي تتذكرها هي الإغلاق (closure). وهي طريقة أنيقة لبناء أداة جاهزة من إعدادات: حاسبة للأسهم وأخرى للصناديق المتداولة.
# A closure remembers the variables of the function that made it
def make_fee_calculator(rate, minimum):
def fee(notional):
return max(minimum, notional * rate)
return fee
stock_fee = make_fee_calculator(0.001, 1.0)
etf_fee = make_fee_calculator(0.0005, 0.5)
print(stock_fee(36850.0)) # 36.85
print(etf_fee(36850.0)) # 18.425حالة تعيش بين الاستدعاءات: nonlocal
يمكن للإغلاق أيضًا تغيير ما يتذكره. ولأن الإسناد سينشئ اسمًا محليًا جديدًا، تعلن الدالة الداخلية أولًا nonlocal count: «هذا الاسم يتبع الدالة المحيطة». ينشئ كل استدعاء للدالة الخارجية ذاكرته المنفصلة، فلا يتداخل عدّادان أبدًا. بهذه الطريقة يحتفظ مولّد معرّفات الأوامر أو المتوسط المتحرك بحالته دون أي متغير عام.
# nonlocal lets the inner function rebind the outer variable
def make_counter():
count = 0
def next_id():
nonlocal count
count += 1
return count
return next_id
order_ids = make_counter()
print(order_ids(), order_ids(), order_ids()) # 1 2 3
other = make_counter()
print(other()) # 1 (its own count)# State between calls: an exponential moving average
def make_ema(alpha):
value = None
def update(price):
nonlocal value
value = price if value is None else alpha * price + (1 - alpha) * value
return value
return update
ema = make_ema(0.5)
print(ema(100.0), ema(110.0), ema(110.0)) # 100.0 105.0 107.5- داخل الدالة تكون الأسماء التي تسندها محلية؛ مرّر البيانات للداخل و
returnللخارج. - الدالة التي تبني دالة وتُرجعها تحوّل الإعدادات إلى أداة.
- استخدم
nonlocalللحالة التي يجب أن تبقى بين الاستدعاءات، ذاكرة واحدة لكل إغلاق.
التالي: اشتقاقات القوائم لبناء قائمة جديدة من أخرى في سطر واحد مقروء.
المختبر: ما الذي يُقيَّم
- ابنِ عدّادًا يتذكر عدّه باستخدام
make_counter25 نقطة - اجمع إعدادات العمولة في دالة باستخدام
make_fee_calculator25 نقطة - احتفظ بمتوسط متحرك بين الاستدعاءات باستخدام
make_ema25 نقطة - أنشئ فحص سعر من حد معيّن باستخدام
make_limit_checker25 نقطة