0Pricing
Python Academy · บทเรียน

functools: lru_cache และ cached_property

แคชการคำนวณที่ใช้เวลานานด้วย lru_cache และ cached_property

functools: lru_cache และ cached_property เป็นบทเรียน Python Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Python Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน

การจดจำผลลัพธ์คืออะไร

การจดจำผลลัพธ์จะเก็บผลลัพธ์ของการเรียกใช้ฟังก์ชันไว้ในแคช โดยใช้ค่าของอาร์กิวเมนต์เป็นคีย์ การเรียกใช้ซ้ำด้วยอาร์กิวเมนต์เดิมจะคืนค่าที่แคชไว้ได้ทันที

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 และการล้าง Cache

ฟังก์ชันที่มีแคชจะแสดง .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 (Least Recently Used) จะนำรายการที่ไม่ได้ถูกใช้งานมานานที่สุดออกเมื่อแคชเต็ม

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 ไม่ปลอดภัยต่อการทำงานหลายเธรด หากหลายเธรดเข้าถึงพร้อมกัน การคำนวณอาจทำงานมากกว่าหนึ่งครั้ง หากจำเป็นให้ใช้ Lock

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 แคชผลลัพธ์ของฟังก์ชันโดยใช้ arguments เป็นคีย์ ซึ่งต้องแฮชได้ @cache เป็นชื่อแทนที่ไม่มีขอบเขต @cached_property แคชการคำนวณคุณสมบัติแยกตามอินสแตนซ์ ตรวจสอบได้ด้วย cache_info() และรีเซ็ตด้วย cache_clear()

คำถามที่พบบ่อย

บทเรียน “functools: lru_cache และ cached_property” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “functools: lru_cache และ cached_property” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Python Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “functools: lru_cache และ cached_property”

แคชการคำนวณที่ใช้เวลานานด้วย lru_cache และ cached_property คุณปฏิบัติ Python Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Python Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Python Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “functools: lru_cache และ cached_property” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Python Academy นี้ได้ไหม

ได้ บทเรียน Python Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. itertools: ตัววนซ้ำแบบไม่สิ้นสุดและมีขอบเขต
  2. itertools: การจัดแบบเชิงการนับ
  3. functools: partial และ reduce
  4. functools: lru_cache และ cached_property
← กลับไปที่ Python Academy