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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- itertools: ตัววนซ้ำแบบไม่สิ้นสุดและมีขอบเขต
- itertools: การจัดแบบเชิงการนับ
- functools: partial และ reduce
- functools: lru_cache และ cached_property