Ачааллж байна...
Өмнөх хичээлд бид closure-ийн үүргэвчийг нээж, дотор нь хуулбар биш, хувьсагчийн хайрцаг буюу cell байдгийг харсан. Тэр хичээлийн бүх closure үүргэвчнээсээ зөвхөн уншсан: мэндчилгээг, үржүүлэгчийг, товчны дугаарыг. Одоо дараагийн алхам. Хэрэв closure тэр хайрцгийн доторх утгыг өөрчлөх шаардлагатай бол яах вэ? Хамгийн энгийн жишээ бол тоолуур: дуудагдах бүрдээ нэгээр нэмэгдэж, одоогийн тоогоо буцаадаг функц. Тоолуур өөрийн тоог хаа нэг газар хадгалах ёстой бөгөөд closure-ийн үүргэвч яг тийм газар мэт санагдана.
Гэвч та үүнийг энгийн байдлаар бичих гэж оролдвол Python гайхмаар алдаа өгнө. Энэ алдааны нэр UnboundLocalError бөгөөд түүний мессеж эхний удаа уншихад утгагүй мэт санагддаг. Энэ хичээлд бид тэр алдааг санаатайгаар гаргаж, Монгол хэлээр уншиж, Python яагаад тэгж бодсоныг бүрэн ойлгоно. Дараа нь шийдлийг нь сурна: nonlocal түлхүүр үг. Энэ нь Python-д "энэ нэр миний шинэ локал хувьсагч биш, үүргэвчинд байгаа хайрцгийг хэлж байна" гэж мэдэгддэг.
Энэ хичээл мөн Хичээл 3.3-т өгсөн амлалтаа биелүүлнэ. Тэнд бид Fibonacci-ийн дуудлагыг тоолохдоо global түлхүүр үг ашигласан бөгөөд үүнээс илүү цэвэр шийдэл closure-оор ирнэ гэж хэлсэн. Хичээлийн төгсгөлд мөн нэг нарийн ялгааг тодорхой болгоно: үүргэвчинд байгаа зүйлийг өөрчлөх ба түүнийг солих хоёрын ялгаа. Нэг нь nonlocal шаарддаг, нөгөө нь шаарддаггүй бөгөөд энэ ялгаа олон хүний будлианы эх үүсвэр болдог.
Үүргэвчтэй хүүхэд рүүгээ буцъя. Одоо түүний орших сургуулийн дотуур байрны өрөөг төсөөлөөд үзээрэй. Өрөөнд түүний өөрийн шүүгээ бий. Энэ бол функцийн Local орон зай. Үүргэвч нь буланд байрлана, дотор нь гэрээс авчирсан хайрцгууд. Энэ бол Enclosing орон зай.
Сургуулийн нэг хатуу дүрэм бий: хэрэв хүүхэд "Тоо" гэсэн шошготой хайрцагт ямар нэг юм тавих гэвэл жижүүр түүнийг өөрийн шүүгээнд тавих ёстой гэж үзнэ. Яагаад гэвэл жижүүр хүүхэд бүрийн үүргэвчийг санамсаргүй өөрчлөгдөхөөс хамгаалах ёстой. Тэгэхээр хүүхэд "Тоо" хайрцагт шинэ зүйл тавихаар шийдмэгц жижүүр "чиний шүүгээнд 'Тоо' хайрцаг байх ёстой" гэж тэмдэглэнэ. Хэрэв хүүхэд тэр хайрцагт юм тавихаасаа өмнө дотор нь юу байгааг харах гэж оролдвол жижүүр "чиний шүүгээний 'Тоо' хайрцаг хоосон, тэнд хараахан юу ч тавиагүй" гэж хэлнэ. Хүүхэд үүргэвчиндээ "Тоо" хайрцаг байгааг мэдэж байгаа ч жижүүр түүнийг харахгүй.
Энэ дүрмийг тойрох зам нь албан ёсны мэдэгдэл. Хүүхэд жижүүрт урьдчилан "Тоо гэдэг хайрцаг миний шүүгээнийх биш, гэрээс авчирсан үүргэвчинд байгаа хайрцаг. Түүнд юм тавих зөвшөөрөл надад бий" гэж хэлбэл жижүүр зөвшөөрнө. Энэ мэдэгдэл бол nonlocal.
Мөн нэг чухал ялгаа бий. Хэрэв хайрцагт дэвтэр байгаа бөгөөд хүүхэд тэр дэвтэрт нэг мөр бичих бол энэ нь хайрцагт "шинэ зүйл тавих" биш. Хайрцагт ижил дэвтэр хэвээр байна, зөвхөн дэвтрийн дотор өөрчлөгдсөн. Жижүүр үүнд санаа зовохгүй. Энэ бол объектыг өөрчлөх ба хайрцгийн агуулгыг солих хоёрын ялгаа бөгөөд Жишээ 2-т бид үүнийг кодоор харна.
Тоолуурыг Хичээл 4.1-ийн function factory загвараар бичих гэж оролдъё.
python
def make_counter():
count = 0
def increment():
count += 1
return count
return increment
counter = make_counter()
print(counter())Ажиллуулахад:
Traceback (most recent call last):
File "C:\python-gunzgii\counter.py", line 12, in <module>
print(counter())
^^^^^^^^^
File "C:\python-gunzgii\counter.py", line 5, in increment
count += 1
^^^^^
UnboundLocalError: cannot access local variable 'count' where it is not associated with a valueTraceback-ийг уншъя. Доод талаас нь эхлэх нь Course 4-өөс танил дадал. Хамгийн сүүлийн мөр: UnboundLocalError: cannot access local variable ‘count’ where it is not associated with a value. Үгчлэн орчуулбал: “‘count’ гэсэн локал хувьсагчид хандах боломжгүй, учир нь түүнд утга холбогдоогүй байна.” Python 3.10 ба түүнээс хуучин хувилбар ижил алдааг “local variable ‘count’ referenced before assignment” буюу "локал хувьсагч ‘count’ утга оноогдохоос өмнө ашиглагдлаа" гэж бичдэг. Хоёр мессеж ижил утгатай. Дээрх мөрүүд алдаа increment функцийн 5-р мөр count += 1 дээр гарсныг, тэр функцийг 12-р мөрөөс дуудсаныг харуулна.
Мессежийн гол үг бол local. Python count-ийг increment-ийн локал хувьсагч гэж үзэж байна. Гэтэл бид count-ийг make_counter дотор тодорхойлсон, increment-ийн дотор биш. Яагаад Python тэгж бодсон бэ? Өмнөх хичээлд greet нь greeting-ийг үүргэвчнээс асуудалгүй олсон шүү дээ.
Яагаад: Python шийдвэрээ урьдчилан гаргадаг
Хариулт нь Python хувьсагч локал эсэхийг хэзээ шийддэгт оршино. Python үүнийг код ажиллах явцад мөр мөрөөр биш, функцийн кодыг бүхэлд нь уншиж, функц объект үүсгэх мөчид нэг удаа шийддэг. Дүрэм энгийн: функцийн биеийн аль ч хэсэгт нэрэнд утга оноож байвал тэр нэр функцийн бүх биеийн туршид локал байна. Утга онооход =, +=, -= гэх мэт бүх оноох үйлдэл, мөн for count in ... ч хамаарна.
count += 1 бол count = count + 1-ийн товчлол. Энд оноох үйлдэл бий. Тиймээс Python increment-ийг үүсгэхдээ “count бол increment-ийн локал хувьсагч” гэж шийдсэн. Зүйрлэлийн жижүүр тэмдэглэв. Үүргэвчинд count байгаа ч Python түүнийг огт харахгүй. Increment ажиллахад баруун талын count + 1 нь локал count-ийг уншихыг оролдоно, гэтэл локал count-д хараахан юу ч оноогдоогүй. Иймд "утга холбогдоогүй локал хувьсагч".
Энэ шийдвэр функцийн бүх биед хамаардгийг баталъя. Доорх функцэд count-ийг эхлээд зөвхөн уншиж, хэвлээд, дараа нь оноож байна:
python
def make_counter():
count = 0
def increment():
print("Одоогийн тоо:", count)
count = 5
return count
return increment
make_counter()()UnboundLocalError: cannot access local variable 'count' where it is not associated with a valueTraceback-ийн дээд хэсгийг товчлон зөвхөн сүүлийн мөрийг үзүүлэв. Алдаа print мөрөн дээр гарсан, тэр мөр зөвхөн уншиж байгаа ч. Учир нь хоёр мөрийн доорх count = 5 мөр Python-ийг increment-ийн бүх биеийн туршид count-ийг локал гэж үзэхэд хүргэсэн. Хэрэв count = 5 мөрийг арилгавал print үүргэвчнээс 0-ийг олж, хэвийн ажиллана. Шийдвэр мөр бүр дээр биш, функцийн хэмжээнд нэг удаа гардаг.
Шийдэл нь increment-ийн эхэнд нэг мөр нэмэх:
python
def make_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter = make_counter()
print(counter())
print(counter())
print(counter())1
2
3nonlocal count нь Python-д хэлж байна: “increment дотор count гэдэг нэр локал биш. Түүнийг хамгийн ойрын гадна функцийн хувьсагч гэж ойлго, тэр хайрцагт утга оноохыг зөвшөөр.” Энэ бол жижүүрт өгсөн албан ёсны мэдэгдэл. Одоо count += 1 нь шинэ локал хувьсагч үүсгэхгүй, үүргэвчин доторх хайрцгийн агуулгыг солино.
Trace: хайрцгийн агуулга хэрхэн өөрчлөгддөг вэ
Алхам 1 (counter = make_counter()). make_counter-ийн гэрт count = 0. increment функц төрөхөд Python түүний кодыг уншиж, nonlocal count-ийг харна. Тиймээс count-ийг локал гэж тооцохгүй, харин гадна гэрийн count-ийн хайрцгийг үүргэвчинд хийнэ. Гэр хаагдана. counter-ийн үүргэвчинд: count хайрцаг, дотор нь 0.
Алхам 2 (эхний counter()). increment-ийн frame үүснэ. Түүний Local орон зай хоосон: count энд байхгүй. count += 1 ажиллахад Python count-ийг үүргэвчнээс уншина: 0. Нэмж 1 болгоно. Үр дүнг ижил хайрцагт буцааж тавина. return count нь хайрцгаас 1-ийг уншиж буцаана. Frame хаагдана. Үүргэвчинд: count хайрцаг, дотор нь 1.
Алхам 3 (хоёр дахь counter()). Шинэ frame. Хайрцагнаас 1-ийг уншина, 2 болгоно, хайрцагт тавина, 2 буцаана. Үүргэвчинд: 2.
Алхам 4 (гурав дахь counter()). Хайрцагт 3. 3 буцна.
Тоолуур хоёр дуудлагын хооронд тоогоо хаана хадгалсныг харлаа уу? increment-ийн frame дуудлага бүрийн дараа хаагддаг тул тэнд хадгалах боломжгүй. Тоо үүргэвчин доторх хайрцагт амьдарч байна. Өмнөх хичээлийн арга ингэж үүнийг шалгана:
python
counter = make_counter()
counter()
counter()
print(counter.__closure__[0].cell_contents)2Хоёр удаа дуудсаны дараа хайрцагт 2 байна. Хайрцаг бодитоор өөрчлөгдсөн.
Хичээл 4.1-ийн бие даасан үүргэвчийн дүрэм энд ч хүчинтэй. Хоёр тоолуур тус тусдаа тоолно:
python
visits = make_counter()
downloads = make_counter()
visits()
visits()
downloads()
print(visits.__closure__[0].cell_contents)
print(downloads.__closure__[0].cell_contents)2
1make_counter-ийн дуудлага бүр шинэ гэр, шинэ count хайрцаг үүсгэсэн. Хоёр тоолуур бие биенээ огт мэдэхгүй.
Жишээ 1: global-ийг closure-оор солих
Хичээл 3.3-т бид Fibonacci-ийн дуудлагыг ингэж тоолсон:
python
calls = 0
def fib_counted(n):
global calls
calls += 1
...Энэ хувилбар ажилладаг ч хоёр асуудалтай. Нэгдүгээрт, calls файлын дээд түвшинд амьдардаг тул файлын аль ч функц түүнийг санамсаргүй өөрчилж чадна. Хоёрдугаарт, хоёр өөр функцийн дуудлагыг тоолох шаардлагатай бол calls_a, calls_b гэх мэт global хувьсагчид нэмэгдсээр байна. Тоолуурыг closure-оор бүтээвэл тус бүр өөрийн хувийн, хамгаалагдсан хайрцагтай болно.
python
def make_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
fib_calls = make_counter()
def fib(n):
fib_calls()
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
fib(20)
print("Дуудлага:", fib_calls.__closure__[0].cell_contents)Дуудлага: 21891Хичээл 3.3-ын тоо 21,891-тэй таарч байна. Одоо тоо файлын дээд түвшний хувьсагчид биш, fib_calls-ийн үүргэвчинд амьдарч байна. Үүнийг өөрчлөх цорын ганц зам нь fib_calls-ийг дуудах явдал. Өөр ямар ч функц санамсаргүй өөрчилж чадахгүй. Хоёр дахь функц тоолох шаардлагатай бол other_calls = make_counter() гэж нэг мөр нэмнэ.
__closure__-ийг нээж тоо уншина гэдэг бол эвгүй, үүнийг дараагийн жишээ шийднэ. Мөн fib дотор fib_calls() гэж гараар бичих нь бас эвгүй. Хэрэв fib-ийг нэг ч мөр өөрчлөхгүйгээр тоолуур нэмж болдог байсан бол? Яг үүнийг decorator хийдэг бөгөөд Бүлэг 5-д бид closure-ийн энэ мэдлэг дээр decorator-ыг бүрэн бүтээнэ.
Жишээ 2: өөрчлөх ба солих — nonlocal хэзээ хэрэгтэй вэ
Одоо зүйрлэлийн "дэвтэрт бичих" хэсэг. Үнэлгээний дундажийг тооцоолдог функц хоёр янзаар бичье. Эхний хувилбар бүх үнэлгээг list-д хадгална:
python
def make_averager():
scores = []
def add(score):
scores.append(score)
return sum(scores) / len(scores)
return add
avg = make_averager()
print(avg(80))
print(avg(90))
print(avg(70))80.0
85.0
80.0nonlocal огт байхгүй ч ажиллаж байна. Яагаад? add-ийн биед scores-д оноох үйлдэл байхгүй. scores.append(score) нь scores нэрэнд шинэ утга оноохгүй, харин scores-ийн заасан list объектын дотрыг өөрчилнө. Хайрцагт ижил list хэвээр, тэр list л уртасч байна. Python-ий "оноож байвал локал" дүрэм идэвхждэггүй тул scores Enclosing-ээс, үүргэвчнээс олдоно. Зүйрлэлээр бол хүүхэд хайрцаг доторх дэвтэрт бичсэн, хайрцагт шинэ зүйл тавиагүй.
Хоёр дахь хувилбар бүх үнэлгээг хадгалахын оронд нийлбэр ба тоог л хадгална. Санах ойн хувьд илүү хэмнэлттэй, Түвшин 1-ийн сэтгэлгээ:
python
def make_averager():
total = 0
count = 0
def add(score):
nonlocal total, count
total += score
count += 1
return total / count
return add
avg = make_averager()
print(avg(80))
print(avg(90))
print(avg(70))80.0
85.0
80.0Энд nonlocal заавал хэрэгтэй. total += score ба count += 1 нь хоёулаа оноох үйлдэл: int бол өөрчлөгдөхгүй объект тул “0 дотор нь 80 нэмэх” боломжгүй, зөвхөн хайрцагт шинэ тоо тавих боломжтой. nonlocal-гүй бол хоёр нэр хоёулаа локал болж UnboundLocalError гарна. Нэг nonlocal мөрөнд хэд хэдэн нэрийг таслалаар зарлаж болно.
Дүрмийг нэгтгэвэл: үүргэвчинд байгаа объектын дотрыг өөрчлөх, тухайлбал list-д append хийх, dict-д түлхүүр нэмэх, set-д элемент нэмэх, nonlocal шаардахгүй. Үүргэвчинд байгаа хайрцгийн агуулгыг солих, тухайлбал =, +=, ялангуяа тоо, string, tuple зэрэг өөрчлөгдөхгүй объектуудад, nonlocal шаарддаг. Энэ ялгаа зөвхөн closure-д биш, Python-ий бүх нэр ба объектын харилцаанд хамаардаг үндсэн санаа.
Жишээ 3: нэг хайрцгийг хуваалцах хэд хэдэн функц
Өмнөх хичээлд нэг гэрт төрсөн хэд хэдэн closure нэг хайрцгийг хуваалцаж, товчны урхи үүсгэсэн. Тэр шинж чанар урхи байсан бол энд түүнийг санаатайгаар ашиглая. Гадна функц нэг биш, хэд хэдэн дотоод функц буцааж, бүгд нэг хайрцгийг хуваалцана.
python
def make_wallet(balance):
def deposit(amount):
nonlocal balance
balance += amount
return balance
def withdraw(amount):
nonlocal balance
if amount > balance:
raise ValueError(f"Үлдэгдэл хүрэлцэхгүй: {balance}")
balance -= amount
return balance
def get_balance():
return balance
return deposit, withdraw, get_balance
deposit, withdraw, get_balance = make_wallet(10000)
deposit(5000)
withdraw(3000)
print(get_balance())
print(deposit.__closure__[0] is withdraw.__closure__[0])12000
Truemake_wallet гурван функцийг tuple болгон буцааж, бид тэдгээрийг гурван нэрэнд задалсан. Гурвуулаа нэг гэрт, нэг дуудлагад төрсөн тул balance-ийн нэг ижил хайрцгийг үүргэвчиндээ авсан. Сүүлийн мөрийн True үүнийг баталж байна. deposit хайрцагт 15000 тавьсны дараа withdraw ижил хайрцгаас 15000-ыг уншиж, 12000 тавьсан. get_balance мөн ижил хайрцгаас уншсан. get_balance-д nonlocal байхгүйг анзаараарай: тэр зөвхөн уншдаг, оноодоггүй. deposit ба withdraw тус бүр өөрийн nonlocal мөртэй байх ёстой, учир нь nonlocal мэдэгдэл функц тус бүрт тусад нь хамаардаг.
Энэ кодыг хараад танд нэг зүйл сануулж магадгүй: нэг өгөгдөл, түүнийг удирддаг хэд хэдэн функц. Энэ бол class-ийн санаа: balance attribute, deposit ба withdraw method. Шударгаар хэлэхэд, хэрэв таны closure гурав, дөрвөн функц буцааж эхэлбэл энэ нь class бичих цаг болсныг илтгэдэг дохио. Closure нэг жижиг төлөв, нэг хоёр функцэд хамгийн тохиромжтой: тоолуур, дундажлагч, тохируулсан функц. Илүү том бүтэц class-д илүү уншигдахуйц. Түвшин 3-т бид энэ хоёрын харилцааг дахин харна. Одоо гол санааг тэмдэглэе: closure ба object хоёулаа "өгөгдөл ба түүнийг хэрэглэдэг код хамт" гэсэн ижил санааны хоёр өөр хэлбэр юм.
Хүсвэл make_counter-ийг алхам тохируулдаг болгож өөрчилж үзээрэй: make_counter(step=1) бөгөөд increment бүр step-ээр нэмэгддэг. step-д nonlocal хэрэгтэй юу, яагаад? Сонирхвол Жишээ 2-ын list хувилбарт scores = scores + [score] гэж append-ийн оронд бичээд юу болохыг таамаглаад шалгаж болно. Энэ мөр өөрчлөх үү, солих уу? Мөн make_wallet-д reset() гэсэн дөрөв дэх функц нэмж, үлдэгдлийг эхний утга руу буцаадаг болгох нь nonlocal ба үүргэвчийн хуваалцлагыг нэг дор туршина. Эдгээр бүгд санал бөгөөд дараагийн хичээлүүд үүнийг хийсэн гэж үзэхгүй.
UnboundLocalError: cannot access local variable ‘count’ where it is not associated with a value. Хичээлийн гол алдаа. "Локал хувьсагч ‘count’-д хандах боломжгүй, түүнд утга холбогдоогүй" гэсэн утгатай. Python 3.10 ба өмнөх хувилбарт “local variable ‘count’ referenced before assignment”. Дотоод функц гадаад хувьсагчид =, += зэргээр оноох үед гарна, учир нь оноолт Python-ийг тэр нэрийг бүх функцийн туршид локал гэж үзэхэд хүргэдэг. Шийдэл нь дотоод функцийн эхэнд nonlocal count нэмэх. Хэрэв таны зорилго гадаад хувьсагчийг өөрчлөх биш, түүнтэй ижил нэртэй шинэ локал хувьсагч үүсгэх байсан бол нэрийг нь өөрчил, ингэснээр уншигчид будлиан үүсэхгүй.
SyntaxError: no binding for nonlocal ‘total’ found. “nonlocal ‘total’-д холбогдох хувьсагч олдсонгүй” гэсэн утгатай. nonlocal-аар зарласан нэр ямар ч гадна функцэд тодорхойлогдоогүй үед гарна. Ихэвчлэн гадна функцэд total = 0 мөрийг мартсан, эсвэл нэрийг өөрөөр бичсэн, жишээлбэл гадна totals, дотор total. Энэ бол SyntaxError тул програм огт эхлэхгүй, Python кодыг уншиж байх үедээ алдааг олдог. nonlocal зөвхөн аль хэдийн байгаа хайрцагт хандах эрх олгодог, шинэ хайрцаг үүсгэдэггүй.
SyntaxError: nonlocal declaration not allowed at module level. "Модулийн түвшинд nonlocal мэдэгдэл зөвшөөрөгдөхгүй" гэсэн утгатай. Энгийн, гадна функцгүй функцэд эсвэл файлын дээд түвшинд nonlocal бичсэн үед гарна. nonlocal нь "гадна функцийн хувьсагч" гэсэн утгатай тул гадна функц байх ёстой. Файлын дээд түвшний хувьсагчийг өөрчлөхийн тулд global байдаг, гэвч Жишээ 1-д харсанчлан ихэнх тохиолдолд closure илүү цэвэр шийдэл.
NameError: name ‘count’ is not defined. “count гэдэг нэр тодорхойлогдоогүй” гэсэн утгатай. nonlocal-ийн оронд санамсаргүй global бичсэн үед гарна: global count. global нь Python-ийг файлын дээд түвшинд хайхад хүргэнэ, гэтэл count make_counter дотор байгаа, дээд түвшинд биш. Хоёр түлхүүр үг төстэй харагдах ч өөр газар заадаг: global бол Global түвшин, nonlocal бол Enclosing түвшин.
SyntaxError: name ‘count’ is used prior to nonlocal declaration. “‘count’ нэр nonlocal мэдэгдлээс өмнө ашиглагдлаа” гэсэн утгатай. nonlocal мөрийг функцийн дунд, нэрийг аль хэдийн ашигласны дараа бичсэн үед гарна. Python nonlocal-ийг функцийн хэмжээний шийдвэр гэж үздэг тул түүнийг функцийн эхэнд, бусад бүх мөрөөс өмнө бичих нь дүрэм.
Python хувьсагч локал эсэхийг функц үүсэх үед, бүх биеийг харж нэг удаа шийддэг: биеийн аль ч хэсэгт =, += зэрэг оноолт байвал тэр нэр бүх функцийн туршид локал. Иймээс closure үүргэвчиндээ байгаа хувьсагчид оноох гэж оролдоход UnboundLocalError гардаг. nonlocal түлхүүр үг тэр нэрийг Enclosing түвшний хайрцаг гэж зарлаж, хайрцгийн агуулгыг солих эрх олгодог. Тоолуурын trace хайрцгийн агуулга дуудлага бүрт өөрчлөгдөж, дуудлага хооронд хадгалагдаж байгааг харуулсан. Үүргэвчин доторх объектын дотрыг өөрчлөх, тухайлбал append, nonlocal шаардахгүй, харин хайрцгийн агуулгыг солих шаарддаг. Нэг гадна функцийн дуудлагад төрсөн хэд хэдэн closure нэг хайрцгийг хуваалцаж болох бөгөөд энэ нь жижиг төлөвтэй объекттой төстэй. Хэрэв closure олон функц буцааж эхэлбэл class илүү тохиромжтой.
Одоо бид closure-ийг уншиж, өөрчилж чаддаг боллоо. Дараагийн хичээлд энэ мэдлэгийг бодит хэрэглээнд оруулна. Closure өдөр тутмын кодонд гурван түгээмэл загвараар гарч ирдэг: урьдчилан тохируулсан форматлагч, хуримтлуулагч, мөн энгийн memo буюу хариултын дэвтэр. Сүүлийнх нь Хичээл 3.3-ын lru_cache-ийг өөрсдөө жижиг хэмжээгээр бүтээх бөгөөд энэ нь Бүлэг 5-ийн decorator-ын шууд гүүр болно.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.