Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. LEGB qoidasi
- 2.2. Kompilyatsiya paytida aniqlanadi
- 2.3. Yopilma (closure)
- 2.4. Sinf qamrovi — maxsus holat
- 2.5. globals(), locals(), vars()
- 2.6. Qamrov va bytecode
- 2.7. Qamrov nozikliklari
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — LEGB namoyishi
- Misol 2 — Yopilma
- Misol 3 — Sinf qamrovi
- Misol 4 — Amaliy: qamrov tahlilchisi
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
7.8-dars: LEGB — ko'rinish sohasi (scope)
7-QISM — FUNKSIYALAR · 8-dars
1. Kirish va motivatsiya
Python nomni qanday topadi?
x = "global"
def f():
x = "lokal"
print(x) # qaysi x?
f() # "lokal"
print(x) # "global"Oddiy ko'rinadi. Lekin:
x = 10
def f():
print(x) # ❌ UnboundLocalError
x = 20
f()Nega print(x) xato beradi, garchi x global bo'lsa ham?
Va:
def tashqi():
x = 1
def ichki():
x = 2 # tashqi x o'zgardimi?
ichki()
return x # 1 yoki 2?Va eng chalkash:
class A:
q = [1, 2, 3]
ikkilangan = [x * 2 for x in q] # ✅
juftliklar = [(x, y) for x in q for y in q] # ❌ NameErrorBu darsda:
- LEGB — nom qidirish tartibi
UnboundLocalErrorva uning sababi- Yopilma (closure) va
__closure__ - Sinf qamrovi — maxsus holat
- Kompilyatsiya paytida aniqlanish
globals(),locals(),vars()
2. Nazariya — chuqur tushuntirish
2.1. LEGB qoidasi
Python nomni to'rt qamrovda ketma-ket qidiradi:
L — Local (funksiya ichi)
E — Enclosing (tashqi funksiya)
G — Global (modul)
B — Built-in (ichki nomlar)x = "global" # G
def tashqi():
x = "enclosing" # E
def ichki():
x = "lokal" # L
print(x) # "lokal"
ichki()
tashqi()Har darajani olib tashlab ko'ring:
x = "global"
def tashqi():
x = "enclosing"
def ichki():
print(x) # "enclosing" — L yo'q
ichki()x = "global"
def tashqi():
def ichki():
print(x) # "global" — L va E yo'q
ichki()def f():
print(len) # <built-in function len> — B Topilmasa — NameError:
def f():
print(aniqlanmagan) # ❌ NameErrorBuilt-in qamrovni ko'rish:
import builtins
print(len(dir(builtins))) # ~150 nom
print([n for n in dir(builtins) if not n.startswith("_")][:10])Ichki nomni yopish:
list = [1, 2] # ⚠️ G darajada
list("abc") # ❌ TypeError — G da topildi, B ga yetmadi2.2. Kompilyatsiya paytida aniqlanadi
Eng muhim tushuncha: Python o'zgaruvchi lokalmi yoki yo'qmi ni kompilyatsiya paytida hal qiladi — kod bajarilishidan oldin.
Qoida: funksiya tanasida nomga o'zlashtirish bo'lsa, u butun funksiya davomida lokal.
x = 10
def f():
print(x) # ❌ UnboundLocalError
x = 20 # ← BU qator x ni lokal qildix = 20 qatori funksiyaning oxirida bo'lsa ham, x butun funksiyada lokal. print(x) bajarilganda u hali qiymat olmagan.
Xato nomi aniq: UnboundLocalError — "lokal, lekin bog'lanmagan".
def f():
print(x)
# UnboundLocalError: cannot access local variable 'x' where it is not
# associated with a valueBytecode farqi:
def global_oqish():
return x # LOAD_GLOBAL
def lokal_oqish():
x = 1
return x # LOAD_FAST
def aralash():
print(x) # LOAD_FAST ← lokal deb hisoblanadi!
x = 1co_varnames — lokal nomlar ro'yxati:
def f():
print(x)
x = 1
f.__code__.co_varnames # ('x',) ← x lokal
f.__code__.co_names # () ← global nom yo'qO'zlashtirishning barcha shakllari nomni lokal qiladi:
def f():
x = 1 # oddiy
x += 1 # ⚠️ ham o'zlashtirish
for x in r: ... # ⚠️
with a as x: ... # ⚠️
except E as x: ... # ⚠️
import x # ⚠️
def x(): ... # ⚠️
class x: ... # ⚠️
x: int = 1 # ⚠️
(x := 1) # ⚠️ walrus
del x # ⚠️ ham! del ham nomni lokal qiladi:
x = 10
def f():
del x # ❌ UnboundLocalErrorFaqat tur ko'rsatkichi — o'zlashtirish EMAS:
x = 10
def f():
x: int # ⚠️ o'zlashtirish yo'q
print(x) # ❌ UnboundLocalError (baribir lokal!)Tur ko'rsatkichi ham nomni lokal qiladi (__annotations__ uchun), lekin qiymat bermaydi.
2.3. Yopilma (closure)
Ichki funksiya tashqi funksiya o'zgaruvchisini eslab qoladi:
def kopaytiruvchi(n):
def ichki(x):
return x * n # ⭐ n — enclosing qamrovdan
return ichki
ikkilash = kopaytiruvchi(2)
ikkilash(5) # 10 n tashqi funksiya tugagandan keyin ham yashaydi.
__closure__ — yopilma hujayralari:
ikkilash.__closure__ # (<cell at 0x...: int object at 0x...>,)
ikkilash.__closure__[0].cell_contents # 2
ikkilash.__code__.co_freevars # ('n',)Bir necha o'zgaruvchi:
def yaratuvchi(a, b, c):
def ichki():
return a + b # faqat a va b ishlatiladi
return ichki
f = yaratuvchi(1, 2, 3)
f.__code__.co_freevars # ('a', 'b') — c yo'qPython faqat ishlatilgan o'zgaruvchilarni saqlaydi.
Yopilma o'zgaruvchisini o'zgartirib bo'lmaydi:
def tashqi():
x = 1
def ichki():
x = 2 # ⚠️ YANGI lokal x
ichki()
return x # 1 — o'zgarmadiBuning uchun nonlocal kerak (9-dars).
Kech bog'lanish (late binding):
funksiyalar = []
for i in range(3):
funksiyalar.append(lambda: i)
[f() for f in funksiyalar] # [2, 2, 2] ⚠️lambda i ni hisoblamaydi, unga havola saqlaydi. Sikl tugaganda i == 2.
Yechim:
funksiyalar = [lambda i=i: i for i in range(3)] # ✅ sukut argumentBu — 6.15-darsda ko'rilgan.
Yopilma o'zgaruvchan obyekt bilan:
def sanagich():
hisob = [0] # ⚠️ ro'yxat — o'zgartirish mumkin
def ichki():
hisob[0] += 1 # ✅ obyektni o'zgartiradi
return hisob[0]
return ichkiBu — nonlocal dan oldingi hiyla. Endi:
def sanagich():
hisob = 0
def ichki():
nonlocal hisob # ✅ aniqroq
hisob += 1
return hisob
return ichki2.4. Sinf qamrovi — maxsus holat
Sinf tanasi — alohida qamrov, lekin u LEGB zanjirida qatnashmaydi:
x = "global"
class A:
x = "sinf"
def metod(self):
return x # "global" ⚠️ sinf x emas!
A().metod() # "global"Sinf atributiga murojaat uchun self.x yoki A.x kerak.
Generatorlar bilan tuzoq:
class A:
q = [1, 2, 3]
ikkilangan = [x * 2 for x in q] # ✅
juftliklar = [(x, y) for x in q for y in q] # ❌ NameError: qSabab:
- Generator — yashirin funksiya (6.15-dars)
- Birinchi
forning iterable'i tashqi qamrovda hisoblanadi →qko'rinadi - Qolgan hamma narsa generator ichida → sinf qamrovi ko'rinmaydi
Yechim:
Q = [1, 2, 3] # modul darajasida
class A:
q = Q
juftliklar = [(x, y) for x in Q for y in Q] # ✅Yoki metod ichida:
class A:
q = [1, 2, 3]
@classmethod
def juftliklar(cls):
return [(x, y) for x in cls.q for y in cls.q] # ✅Nega shunday: sinf tanasi funksiya emas — u bir marta bajariladi va natija type() ga uzatiladi. Uning nom fazosi funksiyalar uchun "ko'rinmas" qilingan — aks holda metodlar ichida sinf atributlariga bevosita murojaat mumkin bo'lardi, va bu self ni ma'nosiz qilardi.
2.5. globals(), locals(), vars()
globals() # modul nom fazosi (dict)
locals() # joriy qamrov (dict)
vars() # locals() bilan bir xil
vars(obj) # obj.__dict__ globals() — haqiqiy lug'at, o'zgartirish ishlaydi:
globals()["yangi"] = 42
print(yangi) # 42 locals() — funksiya ichida NUSXA:
def f():
x = 1
locals()["x"] = 99
return x # 1 ⚠️ o'zgarmadi
def g():
locals()["yangi"] = 1
return yangi # ❌ NameErrorSabab: funksiya lokal o'zgaruvchilari massivda (co_varnames indekslari bo'yicha), lug'atda emas. locals() har chaqiruvda yangi lug'at quradi.
Modul darajasida locals() is globals():
locals() is globals() # True (modul darajasida)Amaliy qo'llanish:
# Debug
def f(a, b):
print(f"argumentlar: {locals()}")
# Formatlash (⚠️ ehtiyotkorlik bilan)
ism, yosh = "Aziz", 30
"{ism} ({yosh})".format(**locals())
# Dinamik nom (⚠️ deyarli har doim noto'g'ri)
globals()[f"o_{i}"] = qiymat # ❌ lug'at ishlating Python 3.13 dan: locals() semantikasi PEP 667 bilan aniqlashtirildi — optimallashtirilgan qamrovlarda u endi mustaqil nusxa.
2.6. Qamrov va bytecode
CPython uch xil yuklash instruksiyasi ishlatadi:
| Instruksiya | Qamrov | Tezlik |
|---|---|---|
LOAD_FAST |
Lokal | Eng tez (massiv indeksi) |
LOAD_DEREF |
Yopilma | Tez (cell obyekti) |
LOAD_GLOBAL |
Global/built-in | Sekinroq (lug'at qidiruvi) |
import dis
def f():
x = 1
return x + len([1]) + GLOBAL_NOM
dis.dis(f)
# LOAD_FAST x ← lokal
# LOAD_GLOBAL len ← built-in
# LOAD_GLOBAL GLOBAL_NOM ← globalTezlik farqi:
# Sekinroq — har iteratsiyada global qidiruv
def sekin(r):
natija = []
for x in r:
natija.append(len(str(x))) # len va str — global
return natija
# Tezroq — lokal nomga ko'chirilgan
def tez(r, _len=len, _str=str):
natija = []
qosh = natija.append
for x in r:
qosh(_len(_str(x)))
return natija Bu — mikro-optimallashtirish. Zamonaviy CPython (3.11+) LOAD_GLOBAL ni keshlaydi, farq kichraydi. O'qilishni qurbon qilmang.
2.7. Qamrov nozikliklari
1. Modul darajasidagi for — lokal emas:
for i in range(3):
pass
print(i) # 2 ✅ ko'rinadiFunksiya ichida ham:
def f():
for i in range(3):
pass
return i # 2 ✅Python da for alohida qamrov yaratmaydi (C, Java dan farqli).
2. if/while/with ham qamrov yaratmaydi:
if True:
x = 1
print(x) # 1 ✅3. except ... as x — blokdan keyin O'CHIRILADI:
try:
raise ValueError
except ValueError as x:
pass
print(x) # ❌ NameErrorBu — ataylab: x istisno obyektiga havola saqlaydi, u esa traceback orqali freym'ga havola qiladi → aylanma havola va xotira sizishi.
Saqlash uchun:
xato = None
try:
...
except ValueError as x:
xato = x # ✅ boshqa nomga4. Generator ifodasi — o'z qamrovi:
x = 10
[x for x in range(3)]
print(x) # 10 ✅ (Python 3)5. Lambda — funksiya qamrovi:
x = 10
f = lambda: x
x = 20
f() # 20 ⚠️ kech bog'lanish6. import — lokal bo'lishi mumkin:
def f():
import math # ⚠️ math lokal
return math.pi
math.pi # ❌ NameError (agar tashqarida import qilinmagan bo'lsa)3. Tez ma'lumotnoma
LEGB tartibi
L — Local funksiya ichi
E — Enclosing tashqi funksiya (yopilma)
G — Global modul
B — Built-in len, print, ...
Topilmasa → NameErrorKompilyatsiya paytida aniqlanadi
x = 10
def f():
print(x) ❌ UnboundLocalError
x = 20 ← BU qator x ni LOKAL qildi
Tanada o'zlashtirish bo'lsa → butun funksiyada LOKAL
O'zlashtirish shakllari:
x = 1, x += 1, for x in, with as x, except as x,
import x, def x, class x, x: int, (x := 1), del xYopilma
def tashqi(n):
def ichki(): return n ⭐ n eslab qolinadi
return ichki
f.__closure__[0].cell_contents
f.__code__.co_freevars
⚠️ x = 2 ichki funksiyada → YANGI lokal (nonlocal kerak)
⚠️ [lambda: i for i in range(3)] → hammasi 2 (kech bog'lanish)Sinf qamrovi
class A:
x = 1
def m(self): return x ⚠️ GLOBAL x, sinf x emas
y = [i for i in x] ✅ birinchi for
z = [(i,j) for i in x for j in x] ❌ NameError
Sinf qamrovi LEGB zanjirida QATNASHMAYDIglobals/locals
globals() haqiqiy dict — o'zgartirish ishlaydi
locals() funksiyada NUSXA — o'zgartirish ishlamaydi
vars() locals() bilan bir xil
vars(obj) obj.__dict__Qamrov yaratmaydi
for, while, if, with, try ✅ qamrov YO'Q — o'zgaruvchi ko'rinadi
except ... as x ⚠️ blokdan keyin O'CHIRILADI
generator/lambda/def/class ✅ o'z qamrovi4. Batafsil misollar
Misol 1 — LEGB namoyishi
"""To'rt qamrov va qidirish tartibi."""
import builtins
print("=== 1. To'rt daraja ===")
x = "GLOBAL"
def tashqi():
x = "ENCLOSING"
def ichki():
x = "LOKAL"
return x
return ichki(), x
def tashqi_lokalsiz():
x = "ENCLOSING"
def ichki():
return x # L yo'q → E
return ichki()
def tashqi_bosh():
def ichki():
return x # L va E yo'q → G
return ichki()
def built_in():
return len # L, E, G yo'q → B
print(f" x = 'GLOBAL' (modul darajasida)\n")
print(f" {'Holat':<32} {'Natija'}")
print(" " + "─" * 56)
print(f" {'L bor':<32} {tashqi()[0]!r}")
print(f" {'L yo`q, E bor':<32} {tashqi_lokalsiz()!r}")
print(f" {'L va E yo`q, G bor':<32} {tashqi_bosh()!r}")
print(f" {'Faqat B':<32} {built_in()}")
print(f"\n Topilmasa:")
try:
def f():
return aniqlanmagan_nom
f()
except NameError as e:
print(f" ❌ NameError: {e}")
print("\n=== 2. Built-in qamrov ===")
ichki_nomlar = [n for n in dir(builtins) if not n.startswith("_")]
print(f" Jami ichki nom: {len(ichki_nomlar)}\n")
TOIFALAR = {
"Funksiyalar": [n for n in ichki_nomlar
if callable(getattr(builtins, n)) and n[0].islower()],
"Turlar": [n for n in ichki_nomlar
if isinstance(getattr(builtins, n), type)
and not n.endswith("Error") and not n.endswith("Warning")],
"Istisnolar": [n for n in ichki_nomlar if n.endswith(("Error", "Exception"))],
"Konstantalar": [n for n in ichki_nomlar
if not callable(getattr(builtins, n))],
}
for toifa, nomlar in TOIFALAR.items():
print(f" {toifa} ({len(nomlar)}):")
print(f" {', '.join(sorted(nomlar)[:12])}...")
print(f"\n ⚠️ Ichki nomni yopish:")
print(f"""
list = [1, 2] # G darajada
list("abc") # ❌ TypeError — G da topildi, B ga yetmadi
""")
_asl_list = list
list = [1, 2]
try:
list("abc")
except TypeError as e:
print(f" ❌ TypeError: {e}")
list = _asl_list
print(f" Tiklandi: list('abc') = {list('abc')}")
print("\n=== 3. ⭐ UnboundLocalError ===")
def yaxshi():
return x # G da topiladi
def yomon():
print(x) # ⚠️ x lokal deb hisoblanadi
x = 20
print(f" x = {x!r}\n")
print(f" def f(): return x")
print(f" → {yaxshi()!r} ✅\n")
print(f" def f():")
print(f" print(x)")
print(f" x = 20")
try:
yomon()
except UnboundLocalError as e:
print(f" → ❌ UnboundLocalError: {e}")
print(f"\n Sabab — bytecode:")
import dis
for f, nom in [(yaxshi, "return x"), (yomon, "print(x); x = 20")]:
instruksiyalar = [i.opname for i in dis.get_instructions(f)
if i.opname.startswith("LOAD")]
print(f" {nom:<24} {instruksiyalar}")
print(f"\n co_varnames (lokal nomlar):")
for f, nom in [(yaxshi, "yaxshi"), (yomon, "yomon")]:
print(f" {nom:<10} varnames={f.__code__.co_varnames}, "
f"names={f.__code__.co_names}")
print("\n=== 4. O'zlashtirishning barcha shakllari ===")
y = "GLOBAL_Y"
SHAKLLAR = [
("y = 1", "def f():\n print(y)\n y = 1"),
("y += 1", "def f():\n print(y)\n y += 1"),
("for y in ...", "def f():\n print(y)\n for y in [1]: pass"),
("with ... as y", "def f():\n print(y)\n with open(__file__) as y: pass"),
("except ... as y", "def f():\n print(y)\n try: pass\n except Exception as y: pass"),
("import y", "def f():\n print(y)\n import y"),
("def y()", "def f():\n print(y)\n def y(): pass"),
("class y", "def f():\n print(y)\n class y: pass"),
("y: int", "def f():\n print(y)\n y: int"),
("(y := 1)", "def f():\n print(y)\n (y := 1)"),
("del y", "def f():\n print(y)\n del y"),
]
print(f" Har birida `print(y)` avval keladi:\n")
print(f" {'Shakl':<20} {'Natija'}")
print(" " + "─" * 56)
for nom, kod in SHAKLLAR:
muhit = {"y": "GLOBAL_Y", "open": open, "__file__": __file__,
"Exception": Exception, "print": lambda *a: None}
try:
exec(kod, muhit)
muhit["f"]()
natija = "✅ global topildi"
except UnboundLocalError:
natija = "❌ UnboundLocalError (lokal)"
except Exception as e:
natija = f"❌ {type(e).__name__}"
print(f" {nom:<20} {natija}")
print(f"\n ⭐ HAMMASI nomni lokal qiladi — hatto `del` va `y: int` ham")
print("\n=== 5. Qamrov yaratmaydigan bloklar ===")
TEKSHIRUVLAR = [
("for", """
for i in range(3):
pass
natija = i
"""),
("while", """
i = 0
while i < 3:
i += 1
natija = i
"""),
("if", """
if True:
j = "if ichida"
natija = j
"""),
("with", """
import io
with io.StringIO("x") as f:
k = "with ichida"
natija = k
"""),
("try", """
try:
m = "try ichida"
except Exception:
pass
natija = m
"""),
("except as", """
try:
raise ValueError("x")
except ValueError as e:
pass
natija = e
"""),
("generator", """
n = "asl"
[n for n in range(3)]
natija = n
"""),
]
print(f" {'Blok':<14} {'Blokdan keyin o`zgaruvchi'}")
print(" " + "─" * 52)
for nom, kod in TEKSHIRUVLAR:
muhit = {}
try:
exec(kod, muhit)
natija = f"✅ {muhit['natija']!r}"
except NameError as e:
natija = f"❌ NameError: {e}"
print(f" {nom:<14} {natija}")
print("""
⭐ for, while, if, with, try — qamrov YARATMAYDI
⚠️ except ... as e — blokdan keyin O'CHIRILADI (aylanma havola oldini olish)
⭐ generator — O'Z qamrovi (Python 3)
""")
print("\n=== 6. globals() va locals() ===")
MODUL_NOM = "modul qiymati"
def qamrovlarni_korsat(a, b=2):
lokal = "lokal qiymat"
def ichki():
return "ichki"
print(f" locals(): {sorted(locals())}")
print(f" globals() da 'MODUL_NOM': {'MODUL_NOM' in globals()}")
print(f" locals() is globals(): {locals() is globals()}")
return locals()
print(f" Funksiya ichida:")
natija = qamrovlarni_korsat(1)
print(f"\n Modul darajasida:")
print(f" locals() is globals(): {locals() is globals()}")
print(f"\n ⚠️ locals() o'zgartirish:")
def locals_ozgartirish():
x = 1
locals()["x"] = 99
return x
print(f" def f(): x = 1; locals()['x'] = 99; return x")
print(f" → {locals_ozgartirish()} ⚠️ o'zgarmadi (nusxa)")
print(f"\n ✅ globals() o'zgartirish:")
globals()["yangi_global"] = 42
print(f" globals()['yangi_global'] = 42")
print(f" yangi_global = {yangi_global} ✅ ishladi")
del globals()["yangi_global"]
print("""
⭐ Sabab: funksiya lokallari MASSIVDA (co_varnames indekslari),
lug'atda emas. locals() har chaqiruvda yangi lug'at quradi.
Modul darajasida esa haqiqatan lug'at ishlatiladi.
""")Natijaning muhim qismi:
=== 1. To'rt daraja ===
Holat Natija
────────────────────────────────────────────────────────
L bor 'LOKAL'
L yo`q, E bor 'ENCLOSING'
L va E yo`q, G bor 'GLOBAL'
Faqat B <built-in function len>
=== 3. ⭐ UnboundLocalError ===
def f():
print(x)
x = 20
→ ❌ UnboundLocalError: cannot access local variable 'x' where it is
not associated with a value
Sabab — bytecode:
return x ['LOAD_GLOBAL']
print(x); x = 20 ['LOAD_GLOBAL', 'LOAD_FAST_CHECK', 'LOAD_SMALL_INT', 'LOAD_CONST']
=== 5. Qamrov yaratmaydigan bloklar ===
Blok Blokdan keyin o`zgaruvchi
────────────────────────────────────────────────────
for ✅ 2
if ✅ 'if ichida'
except as ❌ NameError: name 'e' is not defined
generator ✅ 'asl'Nima ko'rsatdi: 2.1, 2.2, 2.5, 2.7-bo'limlar.
Misol 2 — Yopilma
"""Closure — tashqi o'zgaruvchini eslab qolish."""
print("=== 1. Asosiy yopilma ===")
def kopaytiruvchi(n):
def ichki(x):
return x * n # n — enclosing qamrovdan
return ichki
ikkilash = kopaytiruvchi(2)
uchlash = kopaytiruvchi(3)
onlash = kopaytiruvchi(10)
print(f" ikkilash = kopaytiruvchi(2)")
print(f" uchlash = kopaytiruvchi(3)\n")
print(f" {'x':>4} {'ikkilash':>10} {'uchlash':>10} {'onlash':>10}")
print(" " + "─" * 38)
for x in [1, 5, 10]:
print(f" {x:>4} {ikkilash(x):>10} {uchlash(x):>10} {onlash(x):>10}")
print(f"\n ⭐ kopaytiruvchi() tugagan, lekin n saqlanib qoldi")
print("\n=== 2. __closure__ ichkarisi ===")
print(f" {'Funksiya':<12} {'co_freevars':<16} {'cell_contents'}")
print(" " + "─" * 48)
for nom, f in [("ikkilash", ikkilash), ("uchlash", uchlash),
("onlash", onlash)]:
freevars = f.__code__.co_freevars
qiymatlar = tuple(c.cell_contents for c in f.__closure__)
print(f" {nom:<12} {str(freevars):<16} {qiymatlar}")
print(f"\n Yopilmasiz funksiya:")
def oddiy(x):
return x * 2
print(f" oddiy.__closure__ = {oddiy.__closure__}")
print(f" oddiy.co_freevars = {oddiy.__code__.co_freevars}")
print("\n=== 3. Faqat ishlatilgan o'zgaruvchilar ===")
def yaratuvchi(a, b, c, d):
def faqat_a():
return a
def a_va_b():
return a + b
def hech_qaysi():
return 42
return faqat_a, a_va_b, hech_qaysi
f1, f2, f3 = yaratuvchi(1, 2, 3, 4)
print(f" def yaratuvchi(a, b, c, d): — 4 ta o'zgaruvchi\n")
print(f" {'Ichki funksiya':<16} {'co_freevars':<20} {'Saqlangan'}")
print(" " + "─" * 52)
for nom, f in [("faqat_a", f1), ("a_va_b", f2), ("hech_qaysi", f3)]:
freevars = f.__code__.co_freevars
qiymatlar = (tuple(c.cell_contents for c in f.__closure__)
if f.__closure__ else ())
print(f" {nom:<16} {str(freevars):<20} {qiymatlar}")
print(f"\n ⭐ Python faqat ISHLATILGAN o'zgaruvchilarni saqlaydi")
print("\n=== 4. ⚠️ O'zgartirib bo'lmaydi ===")
def urinish():
x = 1
def ichki():
x = 2 # ⚠️ YANGI lokal x
return x
ichki_natija = ichki()
return x, ichki_natija
tashqi_x, ichki_x = urinish()
print(f" def tashqi():")
print(f" x = 1")
print(f" def ichki():")
print(f" x = 2")
print(f" ichki()")
print(f" return x\n")
print(f" Tashqi x: {tashqi_x} ⚠️ o'zgarmadi")
print(f" Ichki x: {ichki_x}")
print(f"\n ❌ Faqat o'qish urinishi ham xato beradi:")
def uqish_urinishi():
x = 1
def ichki():
print(x) # ⚠️ x lokal deb hisoblanadi
x = 2
return ichki()
try:
uqish_urinishi()
except UnboundLocalError as e:
print(f" ❌ UnboundLocalError: {e}")
print(f"\n ✅ Yechimlar (9-darsda batafsil):")
print(f"""
1. nonlocal x — enclosing o'zgaruvchini o'zgartirish
2. x = [1] — o'zgaruvchan obyekt (eski hiyla)
x[0] = 2
3. Sinf — holat saqlash uchun
""")
print("\n=== 5. ⚠️ Kech bog'lanish ===")
funksiyalar_yomon = []
for i in range(3):
funksiyalar_yomon.append(lambda: i)
print(f" for i in range(3):")
print(f" funksiyalar.append(lambda: i)\n")
print(f" [f() for f in funksiyalar] = {[f() for f in funksiyalar_yomon]}")
print(f" ⚠️ Hammasi 2 — lambda `i` ga HAVOLA saqlaydi\n")
print(f" ✅ Yechimlar:\n")
f1 = [lambda i=i: i for i in range(3)]
print(f" 1. Sukut argument:")
print(f" [lambda i=i: i for i in range(3)] → {[f() for f in f1]}")
from functools import partial
f2 = [partial(lambda x: x, i) for i in range(3)]
print(f"\n 2. functools.partial:")
print(f" [partial(lambda x: x, i) ...] → {[f() for f in f2]}")
def yaratuvchi_f(i):
return lambda: i
f3 = [yaratuvchi_f(i) for i in range(3)]
print(f"\n 3. Yaratuvchi funksiya:")
print(f" [yaratuvchi(i) for i in range(3)] → {[f() for f in f3]}")
print(f"\n Yopilma tarkibi:")
print(f" Yomon: {[f.__code__.co_freevars for f in funksiyalar_yomon]}")
print(f" Yaxshi: {[f.__code__.co_freevars for f in f1]} (sukut argument — freevar emas)")
print("\n=== 6. Yopilma bilan holat ===")
def sanagich_royxat():
"""Eski hiyla — o'zgaruvchan obyekt."""
hisob = [0]
def ichki():
hisob[0] += 1
return hisob[0]
ichki.qiymat = lambda: hisob[0]
ichki.tozala = lambda: hisob.__setitem__(0, 0)
return ichki
def sanagich_nonlocal():
"""✅ Zamonaviy — nonlocal (9-dars)."""
hisob = 0
def ichki():
nonlocal hisob
hisob += 1
return hisob
return ichki
class SanagichSinf:
"""✅ Sinf — eng aniq."""
def __init__(self):
self.hisob = 0
def __call__(self):
self.hisob += 1
return self.hisob
USULLAR = [
("Yopilma + ro'yxat", sanagich_royxat()),
("Yopilma + nonlocal", sanagich_nonlocal()),
("Sinf (__call__)", SanagichSinf()),
]
print(f" {'Usul':<22} {'1':>4} {'2':>4} {'3':>4} Holat")
print(" " + "─" * 54)
for nom, f in USULLAR:
natijalar = [f() for _ in range(3)]
if "ro'yxat" in nom:
holat = "f.__closure__[0].cell_contents[0]"
elif "nonlocal" in nom:
holat = "f.__closure__[0].cell_contents"
else:
holat = "f.hisob"
print(f" {nom:<22} {natijalar[0]:>4} {natijalar[1]:>4} "
f"{natijalar[2]:>4} {holat}")
print("\n=== 7. Amaliy: konfiguratsiyalangan funksiyalar ===")
def validator_yarat(min_qiymat=None, max_qiymat=None, turi=None):
"""Konfiguratsiyalangan validator qaytaradi."""
# turi bitta sinf yoki sinflar korteji bo'lishi mumkin: int yoki (int, float)
turlar = turi if isinstance(turi, tuple) else (turi,) if turi else ()
tur_nomi = " | ".join(t.__name__ for t in turlar)
def tekshir(qiymat):
if turi is not None and not isinstance(qiymat, turi):
return False, f"{tur_nomi} kutildi, {type(qiymat).__name__} keldi"
if min_qiymat is not None and qiymat < min_qiymat:
return False, f"{qiymat} < {min_qiymat}"
if max_qiymat is not None and qiymat > max_qiymat:
return False, f"{qiymat} > {max_qiymat}"
return True, "ok"
qismlar = []
if turi:
qismlar.append(tur_nomi)
if min_qiymat is not None:
qismlar.append(f">={min_qiymat}")
if max_qiymat is not None:
qismlar.append(f"<={max_qiymat}")
tekshir.__name__ = f"validator({', '.join(qismlar)})"
return tekshir
VALIDATORLAR = {
"yosh": validator_yarat(0, 150, int),
"ball": validator_yarat(0, 100, (int, float)),
"maosh": validator_yarat(min_qiymat=0, turi=int),
}
MALUMOT = [
("yosh", 30), ("yosh", -5), ("yosh", 200), ("yosh", "30"),
("ball", 85.5), ("ball", 150),
("maosh", 5_000_000), ("maosh", -100),
]
print(f" {'Maydon':<10} {'Qiymat':<14} {'Natija':<8} Sabab")
print(" " + "─" * 56)
for maydon, qiymat in MALUMOT:
ok, sabab = VALIDATORLAR[maydon](qiymat)
belgi = "✅" if ok else "❌"
print(f" {maydon:<10} {qiymat!r:<14} {belgi:<8} {sabab}")
print(f"\n Har validator o'z konfiguratsiyasini eslab qoldi:")
for nom, v in VALIDATORLAR.items():
qiymatlar = {n: c.cell_contents
for n, c in zip(v.__code__.co_freevars, v.__closure__)}
print(f" {nom:<8} {qiymatlar}")Natijaning muhim qismi:
=== 2. __closure__ ichkarisi ===
Funksiya co_freevars cell_contents
────────────────────────────────────────────────
ikkilash ('n',) (2,)
uchlash ('n',) (3,)
onlash ('n',) (10,)
=== 3. Faqat ishlatilgan o'zgaruvchilar ===
Ichki funksiya co_freevars Saqlangan
────────────────────────────────────────────────────
faqat_a ('a',) (1,)
a_va_b ('a', 'b') (1, 2)
hech_qaysi () ()
=== 5. ⚠️ Kech bog'lanish ===
[f() for f in funksiyalar] = [2, 2, 2]
⚠️ Hammasi 2 — lambda `i` ga HAVOLA saqlaydi
1. Sukut argument:
[lambda i=i: i for i in range(3)] → [0, 1, 2]Nima ko'rsatdi: 2.3-bo'lim.
Misol 3 — Sinf qamrovi
"""Sinf tanasi — LEGB dan tashqarida."""
print("=== 1. Sinf atributi metodda ko'rinmaydi ===")
x = "GLOBAL"
class A:
x = "SINF"
def metod(self):
return x # ⚠️ GLOBAL
def self_bilan(self):
return self.x # ✅ SINF
def sinf_bilan(self):
return A.x # ✅ SINF
a = A()
print(f" x = 'GLOBAL' (modul)")
print(f" class A: x = 'SINF'\n")
print(f" a.metod() → {a.metod()!r} ⚠️ global topildi")
print(f" a.self_bilan() → {a.self_bilan()!r} ✅")
print(f" a.sinf_bilan() → {a.sinf_bilan()!r} ✅")
print("""
⭐ Sinf qamrovi LEGB zanjirida QATNASHMAYDI.
Metod ichidan sinf atributiga faqat self.x yoki A.x orqali.
""")
print("\n=== 2. ⚠️ Generatorlar bilan tuzoq ===")
print(f" class A:")
print(f" q = [1, 2, 3]")
print(f" ikkilangan = [x*2 for x in q] # ?")
print(f" juftliklar = [(x,y) for x in q for y in q] # ?\n")
class B:
q = [1, 2, 3]
ikkilangan = [x * 2 for x in q]
print(f" ✅ ikkilangan = {B.ikkilangan}")
try:
class C:
q = [1, 2, 3]
juftliklar = [(x, y) for x in q for y in q]
except NameError as e:
print(f" ❌ juftliklar → NameError: {e}")
print("""
Sabab:
• Generator — YASHIRIN FUNKSIYA
• BIRINCHI `for` ning iterable'i TASHQI qamrovda hisoblanadi
→ sinf qamrovi ko'rinadi ✅
• Qolgan hamma narsa generator ICHIDA
→ sinf qamrovi KO'RINMAYDI ❌
""")
print(f" Boshqa buziladigan holatlar:")
MISOLLAR = [
("[x for x in q if x in q]", "ikkinchi q — filtr ichida"),
("[q[i] for i in range(3)]", "q generator tanasida"),
("{x: q for x in q}", "qiymat ifodasida q"),
("[i for i in range(len(q))]", "len(q) — birinchi for ichida ✅"),
]
for kod, izoh in MISOLLAR:
try:
exec(f"class T:\n q = [1,2,3]\n r = {kod}")
natija = "✅"
except NameError:
natija = "❌ NameError"
print(f" {kod:<32} {natija:<14} {izoh}")
print("\n=== 3. Yechimlar ===")
Q = [1, 2, 3]
class D:
"""✅ 1. Modul darajasidagi konstanta."""
q = Q
juftliklar = [(x, y) for x in Q for y in Q]
class E:
"""✅ 2. Metod ichida."""
q = [1, 2, 3]
@classmethod
def juftliklar(cls):
return [(x, y) for x in cls.q for y in cls.q]
class F:
"""✅ 3. Oddiy sikl (generator emas)."""
q = [1, 2, 3]
juftliklar = []
for _x in q:
for _y in q:
juftliklar.append((_x, _y))
del _x, _y
from dataclasses import dataclass, field
@dataclass
class G:
"""✅ 4. dataclass + default_factory."""
q: list = field(default_factory=lambda: [1, 2, 3])
@property
def juftliklar(self):
return [(x, y) for x in self.q for y in self.q]
print(f" 1. Modul konstantasi: D.juftliklar[:3] = {D.juftliklar[:3]}")
print(f" 2. Metod ichida: E.juftliklar()[:3] = {E.juftliklar()[:3]}")
print(f" 3. Oddiy sikl: F.juftliklar[:3] = {F.juftliklar[:3]}")
print(f" 4. dataclass: G().juftliklar[:3] = {G().juftliklar[:3]}")
print("\n=== 4. Nega shunday qilingan ===")
print("""
Agar sinf qamrovi funksiyalardan ko'rinsa:
class A:
x = 1
def metod(self):
return x # 1 qaytarardi
Muammolar:
1. self ma'nosiz bo'lardi
— atributga to'g'ridan-to'g'ri murojaat qilinardi
2. Meros buzilardi
— qaysi sinfning x i? O'zi yoki ota-onasi?
3. Obyekt atributi vs sinf atributi
— a.x = 5 dan keyin metod nimani ko'rardi?
4. Dinamik atributlar
— setattr(A, 'y', 1) dan keyin metodlar y ni ko'rardimi?
⭐ Python aniq yo'lni tanladi: self.x yoki A.x.
Bu — Zen ning "Aniq yashirinlikdan yaxshi" tamoyili.
""")
print("\n=== 5. Sinf tanasi — bir marta bajariladi ===")
class H:
print(" (sinf tanasi bajarilmoqda)")
x = 1
print(f" x = {x}, locals() = {sorted(locals())}")
def metod(self):
pass
print(f" metod aniqlangandan keyin: {sorted(locals())}")
print(f"\n H.__dict__ (foydali qismi):")
for k, v in H.__dict__.items():
if not k.startswith("__"):
print(f" {k}: {v}")
print("""
⭐ Sinf tanasi:
1. Alohida nom fazosida bajariladi
2. Natija (locals()) type() ga uzatiladi
3. type() sinf obyektini yaratadi
class A: ... ≈ A = type("A", (), {...})
""")
A_dinamik = type("A_dinamik", (), {"x": 1, "metod": lambda self: self.x})
print(f" type() bilan: A_dinamik().metod() = {A_dinamik().metod()}")
print("\n=== 6. Nested sinf va funksiya ===")
z = "GLOBAL_Z"
def tashqi_funksiya():
z = "ENCLOSING_Z"
class Ichki:
z = "SINF_Z"
def metod(self):
return z # ⚠️ ENCLOSING (sinf emas!)
return Ichki().metod(), Ichki.z
metod_natija, sinf_z = tashqi_funksiya()
print(f" def tashqi():")
print(f" z = 'ENCLOSING_Z'")
print(f" class Ichki:")
print(f" z = 'SINF_Z'")
print(f" def metod(self): return z\n")
print(f" metod() → {metod_natija!r} ⚠️ ENCLOSING, sinf emas")
print(f" Ichki.z → {sinf_z!r}")
print("""
⭐ LEGB zanjiri: metod → Ichki (O'TKAZIB YUBORILADI) → tashqi_funksiya → global
Sinf qamrovi zanjirdan CHIQARIB TASHLANGAN.
""")Natijaning muhim qismi:
=== 1. Sinf atributi metodda ko'rinmaydi ===
a.metod() → 'GLOBAL' ⚠️ global topildi
a.self_bilan() → 'SINF' ✅
=== 2. ⚠️ Generatorlar bilan tuzoq ===
✅ ikkilangan = [2, 4, 6]
❌ juftliklar → NameError: name 'q' is not defined
[x for x in q if x in q] ❌ NameError ikkinchi q — filtr ichida
[q[i] for i in range(3)] ❌ NameError q generator tanasida
[i for i in range(len(q))] ✅ len(q) — birinchi for ichida ✅
=== 6. Nested sinf va funksiya ===
metod() → 'ENCLOSING_Z' ⚠️ ENCLOSING, sinf emas
Ichki.z → 'SINF_Z'Nima ko'rsatdi: 2.4-bo'lim.
Misol 4 — Amaliy: qamrov tahlilchisi
"""Qamrov muammolarini topish va tushunish."""
import dis
import inspect
from types import FunctionType
print("=== Qamrov tahlilchisi ===\n")
def qamrov_tahlili(f) -> dict:
"""Funksiyaning qamrov ishlatishini tahlil qiladi."""
kod = f.__code__
return {
"lokal": kod.co_varnames[:kod.co_argcount + kod.co_kwonlyargcount],
"boshqa_lokal": kod.co_varnames[kod.co_argcount + kod.co_kwonlyargcount:],
"yopilma": kod.co_freevars,
"hujayra": kod.co_cellvars,
"global": kod.co_names,
}
def qamrov_hisoboti(f):
"""Chiroyli hisobot."""
t = qamrov_tahlili(f)
print(f" {f.__name__}:")
for nom, qiymat in t.items():
if qiymat:
print(f" {nom:<16} {qiymat}")
if f.__closure__:
qiymatlar = {n: c.cell_contents
for n, c in zip(f.__code__.co_freevars, f.__closure__)}
print(f" {'saqlangan':<16} {qiymatlar}")
print()
GLOBAL_NOM = "global qiymat"
def oddiy(a, b=2):
lokal = a + b
return lokal + len(str(GLOBAL_NOM))
def yopilma_yaratuvchi(n, m):
def ichki(x):
return x * n + m
return ichki
def hujayra_bilan(n):
def ichki():
return n
ichki()
return n
print("=== 1. Qamrov turlari ===\n")
qamrov_hisoboti(oddiy)
qamrov_hisoboti(yopilma_yaratuvchi(2, 3))
qamrov_hisoboti(hujayra_bilan)
print("=== 2. Bytecode instruksiyalari ===\n")
def aralash(a):
lokal = 1
return lokal + a + GLOBAL_NOM_2 + len([1])
GLOBAL_NOM_2 = 10
INSTRUKSIYALAR = {}
for i in dis.get_instructions(aralash):
if i.opname.startswith("LOAD_"):
INSTRUKSIYALAR.setdefault(i.opname, []).append(i.argrepr)
print(f" def aralash(a):")
print(f" lokal = 1")
print(f" return lokal + a + GLOBAL_NOM_2 + len([1])\n")
IZOHLAR = {
"LOAD_FAST": "lokal (massiv indeksi) — ENG TEZ",
"LOAD_DEREF": "yopilma (cell obyekti) — tez",
"LOAD_GLOBAL": "global/built-in (lug'at) — sekinroq",
"LOAD_CONST": "konstanta",
}
print(f" {'Instruksiya':<16} {'Nomlar':<24} Izoh")
print(" " + "─" * 70)
for opname, nomlar in INSTRUKSIYALAR.items():
izoh = IZOHLAR.get(opname, "")
print(f" {opname:<16} {str(nomlar)[:22]:<24} {izoh}")
print("\n=== 3. Tezlik farqi ===\n")
import timeit
SOZLASH = """
GLOBAL_QIYMAT = 42
r = list(range(1000))
def lokal_bilan(r):
natija = 0
lokal = 42
for x in r:
natija += x + lokal
return natija
def global_bilan(r):
natija = 0
for x in r:
natija += x + GLOBAL_QIYMAT
return natija
def built_in_bilan(r):
natija = 0
for x in r:
natija += len(str(x))
return natija
def lokalga_kochirilgan(r, _len=len, _str=str):
natija = 0
for x in r:
natija += _len(_str(x))
return natija
"""
SINOVLAR = [
("Lokal o'zgaruvchi", "lokal_bilan(r)"),
("Global o'zgaruvchi", "global_bilan(r)"),
("Built-in (len, str)", "built_in_bilan(r)"),
("Lokalga ko'chirilgan", "lokalga_kochirilgan(r)"),
]
natijalar = []
for nom, kod in SINOVLAR:
vaqt = timeit.timeit(kod, setup=SOZLASH, number=2000)
natijalar.append((nom, vaqt))
eng_tez = min(v for _, v in natijalar)
print(f" {'Usul':<26} {'Vaqt':>9} {'Nisbat':>9}")
print(" " + "─" * 48)
for nom, vaqt in natijalar:
print(f" {nom:<26} {vaqt:>7.3f} s {vaqt / eng_tez:>8.2f}x")
print("""
⚠️ Farq kichik (Python 3.11+ LOAD_GLOBAL ni keshlaydi).
Lokalga ko'chirish — faqat isbotlangan tor joyda.
O'qilishni qurbon qilmang.
""")
print("\n=== 4. Muammolarni topish ===\n")
def muammolarni_top(manba: str) -> list[str]:
"""Kodda qamrov muammolarini qidiradi."""
import ast
muammolar = []
daraxt = ast.parse(manba)
for tugun in ast.walk(daraxt):
# 1. Ichki nomlarni yopish
if isinstance(tugun, ast.Assign):
for maqsad in tugun.targets:
if isinstance(maqsad, ast.Name):
import builtins
if hasattr(builtins, maqsad.id):
muammolar.append(
f"{tugun.lineno}: ichki nom yopildi: {maqsad.id!r}"
)
# 2. Sinf tanasida ko'p for li generator
if isinstance(tugun, ast.ClassDef):
for element in tugun.body:
for ichki in ast.walk(element):
if isinstance(ichki, (ast.ListComp, ast.SetComp,
ast.DictComp, ast.GeneratorExp)):
if len(ichki.generators) > 1:
muammolar.append(
f"{ichki.lineno}: sinf tanasida ko'p `for` li "
f"generator — NameError xavfi"
)
# 3. Siklda lambda (kech bog'lanish)
if isinstance(tugun, (ast.For, ast.While)):
for ichki in ast.walk(tugun):
if isinstance(ichki, ast.Lambda):
erkin = {n.id for n in ast.walk(ichki)
if isinstance(n, ast.Name)
and isinstance(n.ctx, ast.Load)}
sikl_ozgaruvchilari = set()
if isinstance(tugun, ast.For) and isinstance(tugun.target, ast.Name):
sikl_ozgaruvchilari.add(tugun.target.id)
if erkin & sikl_ozgaruvchilari:
muammolar.append(
f"{ichki.lineno}: siklda lambda sikl o'zgaruvchisini "
f"ishlatadi — kech bog'lanish"
)
return muammolar
KOD = '''
list = [1, 2, 3]
dict = {}
class A:
q = [1, 2, 3]
yaxshi = [x * 2 for x in q]
yomon = [(x, y) for x in q for y in q]
funksiyalar = []
for i in range(3):
funksiyalar.append(lambda: i)
'''
print(f" Tahlil qilinayotgan kod:")
for i, q in enumerate(KOD.strip().splitlines(), 1):
print(f" {i:>2} │ {q}")
print(f"\n Topilgan muammolar:")
for m in muammolarni_top(KOD):
print(f" ⚠️ {m}")
print("\n=== 5. Qamrov qoidalari xulosasi ===\n")
QOIDALAR = [
("LEGB tartibi",
"Local → Enclosing → Global → Built-in"),
("Lokal aniqlanishi",
"KOMPILYATSIYA paytida: tanada o'zlashtirish bo'lsa — lokal"),
("O'zlashtirish shakllari",
"=, +=, for, with as, except as, import, def, class, :type, :=, del"),
("UnboundLocalError",
"Lokal, lekin hali qiymat olmagan"),
("Yopilma",
"Ichki funksiya tashqi o'zgaruvchini eslab qoladi (__closure__)"),
("Yopilmani o'zgartirish",
"nonlocal kerak (9-dars)"),
("Sinf qamrovi",
"LEGB zanjirida QATNASHMAYDI — self.x yoki A.x"),
("Qamrov yaratmaydi",
"for, while, if, with, try"),
("except as x",
"Blokdan keyin O'CHIRILADI"),
("locals()",
"Funksiyada NUSXA — o'zgartirish ishlamaydi"),
("globals()",
"Haqiqiy lug'at — o'zgartirish ishlaydi"),
]
for nom, izoh in QOIDALAR:
print(f" {nom:<26} {izoh}")Natijaning muhim qismi:
=== 1. Qamrov turlari ===
oddiy:
lokal ('a', 'b')
boshqa_lokal ('lokal',)
global ('len', 'str', 'GLOBAL_NOM')
ichki:
lokal ('x',)
yopilma ('m', 'n')
saqlangan {'m': 3, 'n': 2}
hujayra_bilan:
lokal ('n',)
boshqa_lokal ('ichki',)
hujayra ('n',)
=== 4. Muammolarni topish ===
Topilgan muammolar:
⚠️ 2: ichki nom yopildi: 'list'
⚠️ 3: ichki nom yopildi: 'dict'
⚠️ 8: sinf tanasida ko'p `for` li generator — NameError xavfi
⚠️ 12: siklda lambda sikl o'zgaruvchisini ishlatadi — kech bog'lanishNima ko'rsatdi: 2.2, 2.4, 2.6-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Lokal/global ish vaqtida aniqlanadi" | Kompilyatsiya paytida |
"print(x) global x ni o'qiydi" |
Agar tanada x = ... bo'lsa — UnboundLocalError |
"for alohida qamrov yaratadi" |
Yaratmaydi |
"except as x dan keyin x qoladi" |
O'chiriladi |
| "Sinf atributi metodda ko'rinadi" | self.x kerak |
| "Generatorda sinf atributlari ko'rinadi" | Faqat birinchi for da |
"locals() ni o'zgartirish ishlaydi" |
Funksiyada — yo'q |
| "Yopilma qiymat nusxasini saqlaydi" | Havola saqlaydi (kech bog'lanish) |
"del x global x ni o'chiradi" |
Funksiyada — x ni lokal qiladi |
6. Keng tarqalgan xatolar va yechimlari
1. UnboundLocalError
x = 10
def f():
print(x) # ❌
x = 20
def f():
global x # ✅ (9-dars)
print(x)
x = 20
def f(x_arg=x): # ✅ argument sifatida
print(x_arg)2. Ichki nomni yopish
list = [1, 2] # ❌
royxat = [1, 2] # ✅
list_ = [1, 2] # ✅3. Sinf tanasida ko'p for li generator
class A:
q = [1, 2]
r = [(x, y) for x in q for y in q] # ❌
Q = [1, 2] # ✅
class A:
q = Q
r = [(x, y) for x in Q for y in Q]4. Kech bog'lanish
[lambda: i for i in range(3)] # ⚠️ [2, 2, 2]
[lambda i=i: i for i in range(3)] # ✅ [0, 1, 2]5. Yopilmani o'zgartirish
def tashqi():
x = 1
def ichki():
x = 2 # ⚠️ yangi lokal
...
def tashqi():
x = 1
def ichki():
nonlocal x # ✅
x = 26. except as dan keyin ishlatish
try: ...
except E as x: ...
print(x) # ❌ NameError
xato = None
try: ...
except E as x: xato = x # ✅7. locals() ni o'zgartirish
def f():
locals()["x"] = 1 # ⚠️ ishlamaydi
return x # ❌ NameError8. Metodda sinf atributi
class A:
x = 1
def m(self): return x # ⚠️ global
def m(self): return self.x # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 7.9-dars:
globalvanonlocal - 7.10-dars:
lambdava yopilmalar - 6.15-dars (o'tilgan): generator qamrovi, kech bog'lanish
- 8-qism: sinflar,
self, atributlar - 10-qism: dekoratorlar (yopilmalar asosida)
- 19-qism: modullar,
importva nom fazolari dis,inspect: bytecode va qamrov tahlili
8. Eng yaxshi amaliyotlar
Global o'zgaruvchilardan qoching. Argument sifatida uzating.
Ichki nomlarni yopmang.
list_,id_,type_.Tanada nomga o'zlashtirish bo'lsa — u lokal.
UnboundLocalErrorsababi shu.Sinf atributiga
self.xyokiA.x. Bevosita nom ishlamaydi.Siklda
lambda— sukut argument bilan.lambda i=i: i.except as xnatijasini boshqa nomga saqlang.locals()ni faqat o'qish uchun. O'zgartirish ishlamaydi.Yopilma o'zgaruvchisini o'zgartirish uchun
nonlocal. O'zgaruvchan obyekt hiylasi emas.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
x = "global"
1. def f(): return x
print(f())
2. def f():
x = "lokal"
return x
print(f(), x)
3. def f():
print(x)
x = 1
f()
4. def t():
x = "enc"
def i(): return x
return i()
print(t())
5. def t():
x = "enc"
def i(): x = "in"
i()
return x
print(t())
6. class A:
x = "sinf"
def m(self): return x
print(A().m())
7. for i in range(3): pass
print(i)
8. try: raise ValueError
except ValueError as e: pass
print(e)
9. y = 10
[y for y in range(3)]
print(y)
10. def f():
locals()["z"] = 1
return z
f()
11. def f():
del x
f()
12. print(len([1]) == (lambda: len)()([1]))Javoblar
globallokal global-
UnboundLocalError encenc— ichkixalohidaglobal— sinf qamrovi ko'rinmaydi2—forqamrov yaratmaydi-
NameError—except aso'chiriladi 10— generator o'z qamrovi-
NameError—locals()nusxa -
UnboundLocalError—delham lokal qiladi True
Vazifa 2: Xatolarni tuzating
1. sanoq = 0
def qosh():
sanoq += 1
2. list = [1, 2, 3]
3. class A:
q = [1, 2]
r = [(x,y) for x in q for y in q]
4. fs = [lambda: i for i in range(3)]
5. try: ...
except E as x: ...
print(x)
6. def f():
locals()["x"] = 1
return x
7. class A:
x = 1
def m(self): return x
8. def t():
x = 1
def i(): x = 2
i(); return x # 2 kutilyaptiJavoblar
1. global sanoq (yoki argument/qaytarish)
2. royxat = [1, 2, 3]
3. Q = [1, 2] modul darajasida, keyin [(x,y) for x in Q for y in Q]
4. fs = [lambda i=i: i for i in range(3)]
5. xato = None; except E as x: xato = x
6. def f(): x = 1; return x
7. def m(self): return self.x
8. def i(): nonlocal x; x = 2Vazifa 3: Qamrov tahlilchisi
Vosita yozing:
- Funksiya uchun barcha qamrovlarni ko'rsatsin
- Har nom qaysi qamrovdan kelayotganini
disbilanLOAD_*instruksiyalarini- Yopilma qiymatlarini
- Muammolarni topsin (ichki nom yopish, kech bog'lanish)
- Grafik ko'rinishda chiqarsin
Vazifa 4: Yopilmalar kutubxonasi
Yozing:
sanagich(boshlang'ich=0, qadam=1)— hisoblagichkesh(f)— sodda memoizatsiyachegaralangan(f, n)— n martadan ko'p chaqirilmaydibir_marta(f)— faqat bir marta bajariladikechiktirilgan(f, *args)— keyinroq chaqirish uchun- Har biri uchun
__closure__ni ko'rsating
Vazifa 5: Kech bog'lanish tadqiqoti
Dastur yozing:
- Kech bog'lanish muammosini 5 xil kontekstda ko'rsating
- Har biri uchun 3 xil yechim
__closure__farqini ko'rsating- Tezlikni solishtiring
- Qaysi yechim qachon yaxshiroq
Vazifa 6: Sinf qamrovi tadqiqoti
- Sinf tanasida nima ishlaydi, nima yo'q — to'liq jadval
- Har buziladigan holat uchun 2 yechim
type()bilan dinamik sinf yaratish- Metaclass bilan farq
dataclass,NamedTupleda qanday
Vazifa 7: O'ylash
Nega Python lokal o'zgaruvchini kompilyatsiya paytida aniqlaydi, ish vaqtida emas?
Javob
Sabab: tezlik.
Agar ish vaqtida aniqlansa:
def f():
return xHar x uchun:
- Lokal lug'atda qidirish
- Topilmasa — enclosing
- Topilmasa — global
- Topilmasa — built-in
To'rt lug'at qidiruvi, har murojaatda.
Kompilyatsiya paytida aniqlanganda:
def f():
x = 1
return x # LOAD_FAST 0 ← massiv indeksix — co_varnames dagi 0-indeks. Ish vaqtida:
value = frame->localsplus[0]; // massiv elementiBitta massiv murojaati — lug'at qidiruvidan ~5-10x tez.
Raqamlar:
def lokal():
x = 1
for _ in range(1000):
y = x # LOAD_FAST
def global_():
for _ in range(1000):
y = GLOBAL_X # LOAD_GLOBALLOAD_FAST ~2-3x tezroq (Python 3.11+ da farq kichraydi — LOAD_GLOBAL keshlanadi).
Funksiya chaqiruvi — eng ko'p bajariladigan amal. Uni tezlashtirish butun tilni tezlashtiradi.
Narxi:
1. UnboundLocalError — chalkash xato:
x = 10
def f():
print(x) # ❌
x = 20Yangi boshlovchilar uchun bu — tuzoq. Xato xabari yaxshilangan (Python 3.11+):
UnboundLocalError: cannot access local variable 'x' where it is not
associated with a value2. Dinamik nom yaratish ishlamaydi:
def f():
locals()["x"] = 1
return x # ❌ NameErrorx co_varnames da yo'q — kompilyator uni ko'rmagan.
3. exec funksiya ichida cheklangan:
def f():
exec("x = 1")
return x # ❌ NameErrorexec locals() nusxasini o'zgartiradi, haqiqiy massivni emas.
Boshqa tillar:
| Til | Qamrov aniqlanishi |
|---|---|
| Python | Kompilyatsiya paytida |
JavaScript (let/const) |
Kompilyatsiya paytida (TDZ) |
JavaScript (var) |
Kompilyatsiya (hoisting) |
| Ruby | Kompilyatsiya paytida |
| PHP | Ish vaqtida (dinamik) |
| Lua | Kompilyatsiya paytida |
JavaScript qiziq:
function f() {
console.log(x); // ❌ ReferenceError (TDZ)
let x = 20;
}Bu — Python bilan bir xil muammo. JavaScript uni "Temporal Dead Zone" deb ataydi.
var bilan esa:
function f() {
console.log(x); // undefined (xato yo'q)
var x = 20;
}Bu — yomonroq: xato yo'q, lekin undefined. Python UnboundLocalError bilan aniqroq.
Muqobil dizayn bo'lardimi?
Variant A: Global deb hisoblash, keyin lokal
x = 10
def f():
print(x) # 10
x = 20 # endi lokal
print(x) # 20Muammo: bir nom ikki ma'noga ega. Kod kuzatish qiyin. Va tezlik yo'qoladi.
Variant B: Aniq e'lon (var x)
def f():
var x # aniq lokal
print(x)Muammo: Pythonning "e'lon yo'q" falsafasiga zid. Kod uzunroq.
Variant C: Hozirgi (Python tanlagan)
Bir qoida: "tanada o'zlashtirish bo'lsa — lokal". Sodda va tez.
Xulosa: bu — tezlik uchun to'langan narx. Qoida bir jumlada tushuntiriladi, va global/nonlocal bilan hal qilinadi. Xato xabari ham aniq. Amalda muammo faqat yangi boshlovchilarda va bir marta uchraydi — keyin qoida o'zlashadi.
Nimani mustahkamlaydi: 2.1, 2.2, 2.6-bo'limlar.
Xulosa
Bu darsda LEGB qoidasini o'rgandik.
Eng muhim uch fikr:
LEGB: Local → Enclosing → Global → Built-in. Python nomni shu tartibda qidiradi. Topilmasa
NameError.Lokal/global kompilyatsiya paytida aniqlanadi. Funksiya tanasida nomga o'zlashtirish bo'lsa (
=,+=,for,with as,import, hattodel), u butun funksiya davomida lokal. Shuning uchunprint(x)dan keyinx = 1yozilsa —UnboundLocalError.Sinf qamrovi LEGB zanjirida qatnashmaydi. Metod ichidan sinf atributiga faqat
self.xyokiA.xorqali. Va sinf tanasidagi ko'pforli generatorNameErrorberadi — chunki generator yashirin funksiya, undan sinf qamrovi ko'rinmaydi.
Keyingi darsda global va nonlocal ni ko'ramiz: qamrov qoidasini ataylab buzish, qachon kerak va qachon yomon dizayn belgisi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!