functools: lru_cache وcached_property
خزّن نتائج العمليات الحسابية المكلفة مؤقتاً باستخدام lru_cache وcached_property
functools: lru_cache وcached_property درس مجاني في Python Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Python Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Python Academy 4 دروس في المجموع.
ما هو Memoization؟
يخزّن Memoization نتيجة استدعاء الدالة مؤقتًا، مع ربطها بوسائطها. وتُعيد الاستدعاءات المتكررة بالوسائط نفسها النتيجة المخزنة مؤقتًا فورًا.
def slow_fib(n):
if n < 2: return n
return slow_fib(n-1) + slow_fib(n-2)
# slow_fib(35) makes ~29 million calls
# With caching it makes only 35@lru_cache
يخزّن @functools.lru_cache(maxsize=128) ما يصل إلى maxsize من النتائج الحديثة. اضبط maxsize=None لإنشاء ذاكرة تخزين مؤقتة غير محدودة.
import functools
@functools.lru_cache(maxsize=None)
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
print(fib(50)) # instant@cache — Python 3.9+
functools.cache اختصار لـ lru_cache(maxsize=None) — ذاكرة تخزين مؤقتة غير محدودة باسم أوضح.
import functools
@functools.cache
def factorial(n):
return n * factorial(n-1) if n else 1
print(factorial(10)) # 3628800معلومات الذاكرة المؤقتة ومسحها
توفّر الدوال ذات النتائج المخزنة مؤقتًا .cache_info() (عدد مرات الإصابة والإخفاق والحجم) و.cache_clear().
import functools
@functools.lru_cache(maxsize=100)
def square(n):
return n * n
for i in range(5): square(i % 3)
print(square.cache_info())
# CacheInfo(hits=2, misses=3, maxsize=100, currsize=3)
square.cache_clear()سياسة الإخلاء LRU
تُخلي LRU (الأقل استخدامًا مؤخرًا) العنصر الذي تم الوصول إليه بأقل تكرار عند امتلاء الذاكرة المؤقتة.
import functools
@functools.lru_cache(maxsize=3)
def compute(n):
print(f"computing {n}")
return n**2
for x in [1,2,3,4,1]: # 4 evicts 1 (LRU), then 1 re-computes
compute(x)الوسائط القابلة للتجزئة فقط
تتطلب lru_cache أن تكون جميع الوسائط قابلة للتجزئة. القوائم والقواميس غير قابلة للتجزئة؛ لذا استخدم الصفوف بدلًا منها.
import functools
@functools.lru_cache(maxsize=None)
def sum_tuple(t): # tuple is hashable
return sum(t)
print(sum_tuple((1,2,3))) # 6
# sum_tuple([1,2,3]) # TypeError@cached_property
تحسب functools.cached_property خاصيةً مرة واحدة، ثم تخزّن النتيجة في الكائن، مستبدلةً الواصف بالقيمة.
import functools
class Circle:
def __init__(self, r):
self.r = r
@functools.cached_property
def area(self):
import math
print("computing...")
return math.pi * self.r ** 2
c = Circle(5)
print(c.area) # computing... 78.53...
print(c.area) # 78.53... (cached, no print)cached_property مقارنةً بـ property
تعيد @property الحساب عند كل وصول. أما @cached_property فتحسب مرة واحدة وتخزّن النتيجة في instance.__dict__.
import functools
class Expensive:
@property
def always(self): # runs every access
return sum(range(1_000_000))
@functools.cached_property
def once(self): # runs only first access
return sum(range(1_000_000))أمان cached_property في الخيوط
لا تُعد cached_property آمنةً مع الخيوط. فإذا وصلت إليها خيوط متعددة في الوقت نفسه، فقد يُنفَّذ الحساب أكثر من مرة. استخدم قفلًا عند الحاجة.
import functools, threading
class SafeCache:
_lock = threading.Lock()
@functools.cached_property
def data(self):
with self._lock:
return expensive_computation()إبطال cached_property
احذف سمة الكائن لإبطال الذاكرة المؤقتة وفرض إعادة الحساب عند الوصول التالي.
import functools
class Report:
@functools.cached_property
def summary(self):
return compute_summary()
r = Report()
_ = r.summary # computed
del r.summary # invalidate
_ = r.summary # recomputedاستخدام lru_cache كذاكرة مؤقتة لواجهة API
خزّن استجابات API مؤقتًا خلال الجلسة لتجنّب استدعاءات الشبكة المكررة. امسح الذاكرة المؤقتة عند الحاجة إلى بيانات حديثة.
import functools, urllib.request, json
@functools.lru_cache(maxsize=32)
def get_user(user_id):
url = f"https://api.example.com/users/{user_id}"
with urllib.request.urlopen(url) as r:
return json.loads(r.read())
user = get_user(42) # network call
user = get_user(42) # cachedتحقق سريع
ما الطريقة التي تمسح جميع النتائج المخزنة مؤقتًا لدالة مزينة باستخدام @lru_cache؟
مراجعة
تخزّن @lru_cache نتائج الدوال مؤقتًا مع ربطها بالوسائط، التي يجب أن تكون قابلة للتجزئة. و@cache اسم بديل غير محدود. أما @cached_property فتخزّن نتيجة حساب الخاصية مؤقتًا لكل كائن. افحصها باستخدام cache_info() وأعد ضبطها باستخدام cache_clear().
الأسئلة الشائعة
هل درس «functools: lru_cache وcached_property» مجاني؟
نعم — نص درس «functools: lru_cache وcached_property» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Python Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Python Academy 4 دروس في المجموع.
ماذا ستتعلم في «functools: lru_cache وcached_property»؟
خزّن نتائج العمليات الحسابية المكلفة مؤقتاً باستخدام lru_cache وcached_property تتمرن على Python Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Python Academy؟
لا تُشترط خبرة سابقة. Python Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «functools: lru_cache وcached_property»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Python Academy هذا؟
نعم. كل درس في Python Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- itertools: المكرّرات اللانهائية والمحدودة
- itertools: التوافقيات
- functools: partial وreduce
- functools: lru_cache وcached_property