Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. global
- 2.2. nonlocal
- 2.3. Qachon kerak, qachon yomon
- 2.4. Modul darajasidagi holat
- 2.5. Ko'p oqimli kod
- 2.6. Nozikliklar
- 2.7. Muqobil vositalar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — global
- Misol 2 — nonlocal
- Misol 3 — Muqobillar va ko'p oqim
- Misol 4 — Amaliy: modul holati va refaktoring
- 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.9-dars: global va nonlocal
7-QISM — FUNKSIYALAR · 9-dars
1. Kirish va motivatsiya
8-darsda ko'rdik: funksiya tanasida nomga o'zlashtirish bo'lsa — u lokal.
sanoq = 0
def qosh():
sanoq += 1 # ❌ UnboundLocalError
qosh()Va yopilmada ham:
def sanagich():
hisob = 0
def ichki():
hisob += 1 # ❌ UnboundLocalError
return hisob
return ichkiIkki kalit so'z bu qoidani ataylab buzadi:
sanoq = 0
def qosh():
global sanoq # ⭐ "sanoq — modul darajasida"
sanoq += 1
def sanagich():
hisob = 0
def ichki():
nonlocal hisob # ⭐ "hisob — tashqi funksiyada"
hisob += 1
return hisob
return ichkiLekin ular — oxirgi chora. Ko'p holatda global holat yomon dizayn belgisi:
# ❌ Global holat
jami = 0
def qosh(x):
global jami
jami += x
# ✅ Qaytarish
def qosh(jami, x):
return jami + x
# ✅ Sinf
class Hisoblagich:
def __init__(self): self.jami = 0
def qosh(self, x): self.jami += xBu darsda:
global— modul qamroviga yozishnonlocal— enclosing qamroviga yozish- Qachon kerak, qachon yomon dizayn
- Muqobillar: qaytarish, sinf,
itertools.count - Ko'p oqimli kod va global holat
- Modullar orasida global o'zgaruvchilar
2. Nazariya — chuqur tushuntirish
2.1. global
sanoq = 0
def qosh():
global sanoq # "sanoq lokal EMAS, modul darajasida"
sanoq += 1
qosh()
print(sanoq) # 1 global nima qiladi:
Kompilyatorga aytadi: bu nom lokal emas, uni modul nom fazosida qidir va yoz.
Bytecode:
def globalsiz():
x = 1 # STORE_FAST
def global_bilan():
global x
x = 1 # STORE_GLOBAL O'qish uchun global KERAK EMAS:
x = 10
def f():
return x # ✅ global topiladi
def g():
global x # ⚠️ ortiqcha
return xglobal faqat yozish uchun kerak.
Yangi global yaratish:
def f():
global yangi
yangi = 42
f()
print(yangi) # 42 ✅Bir necha nom:
global a, b, c global funksiya boshida bo'lishi shart emas, lekin:
def f():
x = 1 # lokal
global x # ❌ SyntaxError: name 'x' is assigned to before
# global declarationE'lon birinchi ishlatishdan oldin bo'lishi kerak.
global argumentga qo'llanmaydi:
def f(x):
global x # ❌ SyntaxError: name 'x' is parameter and globalModul darajasida global — ma'nosiz:
global x # ⚠️ ishlaydi, lekin hech narsa qilmaydi
x = 12.2. nonlocal
Python 3.0+ (PEP 3104). Enclosing qamrovdagi o'zgaruvchini o'zgartiradi:
def tashqi():
x = 1
def ichki():
nonlocal x
x = 2
ichki()
return x # 2 ✅
tashqi() # 2 nonlocal va global farqi:
global |
nonlocal |
|
|---|---|---|
| Qamrov | Modul (G) | Eng yaqin enclosing (E) |
| Nom mavjud bo'lishi | Shart emas (yaratadi) | Shart |
| Modul darajasida | Ma'nosiz | SyntaxError |
| Global ni topadi | Yo'q |
Nom enclosing da mavjud bo'lishi SHART:
def tashqi():
def ichki():
nonlocal x # ❌ SyntaxError: no binding for nonlocal 'x' found
x = 1
ichki() nonlocal global ni topmaydi:
x = 10
def f():
nonlocal x # ❌ SyntaxError
x = 20Global uchun global kerak.
Eng yaqin enclosing:
def a():
x = "a"
def b():
x = "b"
def c():
nonlocal x # ⭐ b ning x i (a niki emas)
x = "c"
c()
return x # "c"
return b(), x # ("c", "a")Bir necha daraja yuqoriga:
def a():
x = "a"
def b():
def c():
nonlocal x # ⭐ a ning x i (b da x yo'q)
x = "c"
c()
b()
return x # "c"nonlocal eng yaqin x bor bo'lgan enclosing qamrovni topadi.
2.3. Qachon kerak, qachon yomon
Global holat — kamdan-kam to'g'ri.
Muammolar:
- Test qilish qiyin — holatni tiklash kerak
- Ko'p oqimda xavfli — poyga holati (race condition)
- Bog'liqlik yashirin — funksiya imzosida ko'rinmaydi
- Qayta ishlatib bo'lmaydi — bitta global holat
- Kuzatish qiyin — kim o'zgartirdi?
Muqobillar:
# ❌ Global
jami = 0
def qosh(x):
global jami
jami += x
# ✅ 1. Qaytarish (toza funksiya)
def qosh(jami, x):
return jami + x
# ✅ 2. Sinf (holat obyektda)
class Hisoblagich:
def __init__(self):
self.jami = 0
def qosh(self, x):
self.jami += x
return self.jami
# ✅ 3. Yopilma (nonlocal bilan)
def hisoblagich_yarat():
jami = 0
def qosh(x):
nonlocal jami
jami += x
return jami
return qosh
# ✅ 4. Tayyor vosita
from itertools import count
sanagich = count()
next(sanagich)Qachon global maqbul:
| Holat | Izoh |
|---|---|
| Modul konstantalari | _KESH, _SOZLAMALAR — kirish nuqtalari orqali |
| Singleton (bir marta ishga tushirish) | _ulanish |
Kesh (functools ichida ham shunday) |
_KESH = {} |
| Skript (kichik, bir martalik) | Prototip uchun |
| Legacy kod bilan integratsiya | Boshqa yo'l yo'q |
Qachon nonlocal maqbul:
| Holat | Izoh |
|---|---|
| Dekoratorlarda hisoblagich | chaqiruvlar += 1 |
| Yopilma bilan holat | Kichik, mahalliy |
| Callback'da natija to'plash | GUI, hodisa tizimlari |
| Rekursiv funksiyada akkumulyator | Ba'zan nonlocal aniqroq |
Lekin ko'pincha sinf yaxshiroq:
# nonlocal bilan
def sanagich():
hisob = 0
def ichki():
nonlocal hisob
hisob += 1
return hisob
ichki.tozala = lambda: None # ⚠️ hisob ni tozalab bo'lmaydi
return ichki
# Sinf bilan — to'liq nazorat
class Sanagich:
def __init__(self):
self.hisob = 0
def __call__(self):
self.hisob += 1
return self.hisob
def tozala(self):
self.hisob = 02.4. Modul darajasidagi holat
Modul — singleton. U bir marta import qilinadi:
# sozlamalar.py
_KESH = {}
_ULANISH = None
def ulanish_ol():
global _ULANISH
if _ULANISH is None:
_ULANISH = ulan() # bir marta
return _ULANISH
def keshga_yoz(kalit, qiymat):
_KESH[kalit] = qiymat # ⭐ global KERAK EMAS — o'zgartirishMuhim farq:
_KESH = {}
def f():
_KESH["a"] = 1 # ✅ global kerak EMAS (obyektni o'zgartirish)
def g():
global _KESH
_KESH = {} # ✅ global KERAK (qayta bog'lash)Bu — 7.2-darsdagi "o'zgartirish vs qayta bog'lash" farqi.
from modul import x — nusxa oladi:
# a.py
x = 1
def ozgartir():
global x
x = 2
# b.py
from a import x, ozgartir
ozgartir()
print(x) # 1 ⚠️ o'zgarmadi!
import a
a.ozgartir()
print(a.x) # 2 ✅from a import x — x ning joriy qiymatiga yangi nom bog'laydi. Keyingi o'zgarishlar ko'rinmaydi.
Shuning uchun o'zgaruvchan global holat uchun import modul ishlating.
2.5. Ko'p oqimli kod
Global holat — poyga holati (race condition):
import threading
sanoq = 0
def qosh():
global sanoq
for _ in range(100_000):
sanoq += 1 # ⚠️ atomik EMAS
oqimlar = [threading.Thread(target=qosh) for _ in range(2)]
for o in oqimlar: o.start()
for o in oqimlar: o.join()
print(sanoq) # ⚠️ 200000 bo'lishi KAFOLATLANMAGANBu kodni hozirgi CPython (3.10+) da ishga tushirsangiz, ehtimol 200000 chiqadi — va "demak xavfsiz" degan xulosaga kelish oson. Bu xato xulosa:
sanoq += 1baribir uch qadam: o'qish → hisoblash → yozish.- GIL iplarni odatda aynan shu qadamlar orasida almashtirmaydi, shuning uchun yo'qotish kamdan-kam ko'rinadi — lekin bu til kafolati emas, CPython'ning ichki tafsiloti.
- Free-threaded Python (3.13t va undan keyingi, GIL'siz) da, PyPy va boshqa implementatsiyalarda qiymatlar haqiqatan yo'qoladi.
- O'qish va yozish orasida funksiya chaqiruvi, I/O yoki
sleepbo'lsa (real kodda deyarli doim shunday), yo'qotish CPython'da ham darhol ko'rinadi (4-misol).
Qoida: umumiy holat o'zgarsa — threading.Lock, queue.Queue yoki global holatdan voz kechish.
Sabab: sanoq += 1 uch amaldan iborat:
LOAD_GLOBAL sanoq
ADD 1
STORE_GLOBAL sanoqOqim ular orasida uzilishi mumkin.
Yechimlar:
# 1. Lock
qulf = threading.Lock()
def qosh():
global sanoq
for _ in range(100_000):
with qulf:
sanoq += 1 # ✅ atomik
# 2. threading.local — har oqimga o'z holati
lokal = threading.local()
def qosh():
lokal.sanoq = getattr(lokal, "sanoq", 0) + 1
# 3. Queue — oqimlar orasida ma'lumot
from queue import Queue
natijalar = Queue()
# 4. Global holatdan umuman voz kechish ⭐
def qosh(n):
return sum(1 for _ in range(n))GIL global holatni himoya QILMAYDI:
GIL bir vaqtda bitta bytecode instruksiyasini kafolatlaydi, lekin += — bir nechta instruksiya (o'qish → hisoblash → yozish).
2.6. Nozikliklar
1. global tanani skanerlashda ishlaydi:
def f():
if False:
global x # ⚠️ shart bajarilmasa ham ta'sir qiladi
x = 1 # global x
f()
print(x) # 1Kompilyator butun tanani ko'radi — shart ahamiyatsiz.
2. global ichma-ich funksiyada:
def tashqi():
def ichki():
global x # ⭐ MODUL darajasi, tashqi emas
x = 1
ichki()
tashqi()
print(x) # 13. nonlocal + global birga:
def f():
x = 1
def g():
nonlocal x
global y
x = 2
y = 3
g()
return x4. Sinf tanasida:
x = 1
class A:
global x
x = 2 # ⚠️ modulning x i o'zgardi
print(x) # 2
print(A.x) # ❌ AttributeErrorKamdan-kam ishlatiladi va chalkash.
5. exec bilan:
def f():
exec("global x; x = 1")
return x # ❌ NameError
def f():
exec("global x; x = 1", globals())
return globals()["x"] # ✅6. Lambda da ishlatib bo'lmaydi:
f = lambda: global x # ❌ SyntaxErrorlambda faqat ifoda, global — buyruq.
2.7. Muqobil vositalar
itertools.count — hisoblagich:
from itertools import count
sanagich = count(1)
next(sanagich) # 1
next(sanagich) # 2functools.lru_cache — kesh:
@lru_cache(maxsize=128)
def qimmat(n): ...contextvars — kontekstga bog'liq holat (async uchun):
from contextvars import ContextVar
joriy_foydalanuvchi = ContextVar("foydalanuvchi", default=None)
joriy_foydalanuvchi.set("aziz")
joriy_foydalanuvchi.get()threading.local — oqimga bog'liq holat:
import threading
lokal = threading.local()
lokal.malumot = "har oqimga alohida"Funksiya atributi:
def f():
f.chaqiruvlar += 1
return f.chaqiruvlar
f.chaqiruvlar = 0dataclass — holat konteyneri:
@dataclass
class Holat:
sanoq: int = 0
kesh: dict = field(default_factory=dict)3. Tez ma'lumotnoma
global
global x "x — MODUL darajasida"
O'qish uchun KERAK EMAS
Yozish (qayta bog'lash) uchun KERAK
Yangi global yaratadi
Bir necha nom: global a, b, c
❌ def f(x): global x parametr
❌ x = 1; global x o'zlashtirishdan keyinnonlocal
nonlocal x "x — ENG YAQIN enclosing qamrovda"
⚠️ Nom mavjud bo'lishi SHART
❌ Modul darajasida — SyntaxError
❌ Global ni TOPMAYDIFarq
global nonlocal
Qamrov modul (G) enclosing (E)
Mavjudlik shart emas SHART
Yaratadi ✅ ❌O'zgartirish vs qayta bog'lash
_KESH = {}
def f(): _KESH["a"] = 1 ✅ global KERAK EMAS
def g(): global _KESH; _KESH = {} ✅ global KERAKfrom import
from a import x nusxa — keyingi o'zgarish KO'RINMAYDI
import a; a.x ✅ har doim joriy qiymatMuqobillar
Qaytarish (toza funksiya) ⭐ eng yaxshi
Sinf holat + metodlar
Yopilma + nonlocal kichik, mahalliy
itertools.count hisoblagich
functools.lru_cache kesh
threading.local oqimga bog'liq
contextvars async kontekst
Funksiya atributi f.hisobKo'p oqim
sanoq += 1 ATOMIK EMAS (o'qish → hisoblash → yozish) → race condition
→ threading.Lock, Queue, yoki global holatdan voz kechish4. Batafsil misollar
Misol 1 — global
"""global — modul qamroviga yozish."""
import dis
print("=== 1. Muammo va yechim ===")
sanoq = 0
def qosh_yomon():
sanoq += 1 # ⚠️
def qosh_yaxshi():
global sanoq
sanoq += 1
print(f" sanoq = {sanoq}\n")
print(f" def qosh(): sanoq += 1")
try:
qosh_yomon()
except UnboundLocalError as e:
print(f" → ❌ UnboundLocalError: {e}\n")
print(f" def qosh():")
print(f" global sanoq")
print(f" sanoq += 1")
qosh_yaxshi()
qosh_yaxshi()
print(f" → ✅ sanoq = {sanoq}")
print("\n=== 2. O'qish uchun kerak emas ===")
x = "GLOBAL"
def faqat_oqish():
return x # ✅ global kerak emas
def ortiqcha_global():
global x # ⚠️ ortiqcha
return x
print(f" x = {x!r}\n")
print(f" def f(): return x → {faqat_oqish()!r} ✅")
print(f" def f(): global x; return x → {ortiqcha_global()!r} ⚠️ ortiqcha")
print(f"\n Bytecode:")
for f, nom in [(faqat_oqish, "global siz"), (ortiqcha_global, "global bilan")]:
ins = [i.opname for i in dis.get_instructions(f) if "LOAD" in i.opname]
print(f" {nom:<16} {ins}")
print(f"\n ⭐ Ikkalasi ham LOAD_GLOBAL — farq yo'q")
print("\n=== 3. Yozish uchun kerak ===")
def yozish_global_siz():
global_test = "lokal" # yangi lokal
return global_test
global_test = "GLOBAL"
def yozish_global_bilan():
global global_test
global_test = "o'zgartirildi"
print(f" global_test = {global_test!r}\n")
yozish_global_siz()
print(f" global siz yozish → global_test = {global_test!r} (o'zgarmadi)")
yozish_global_bilan()
print(f" global bilan yozish → global_test = {global_test!r} ✅")
print(f"\n Bytecode:")
for f, nom in [(yozish_global_siz, "global siz"),
(yozish_global_bilan, "global bilan")]:
ins = [i.opname for i in dis.get_instructions(f) if "STORE" in i.opname]
print(f" {nom:<16} {ins}")
print("\n=== 4. ⚠️ O'zgartirish vs qayta bog'lash ===")
_KESH = {"boshlangich": 1}
_ROYXAT = [1, 2]
def ozgartirish():
"""✅ global KERAK EMAS — obyektni o'zgartiradi."""
_KESH["yangi"] = 2
_ROYXAT.append(3)
def qayta_boglash_siz():
"""⚠️ Yangi lokal yaratadi."""
_KESH = {}
_ROYXAT = []
def qayta_boglash_bilan():
"""✅ global KERAK."""
global _KESH, _ROYXAT
_KESH = {"tozalandi": True}
_ROYXAT = []
print(f" Boshlang'ich: _KESH={_KESH}, _ROYXAT={_ROYXAT}\n")
ozgartirish()
print(f" Obyektni o'zgartirish (global siz):")
print(f" _KESH={_KESH}, _ROYXAT={_ROYXAT} ✅ o'zgardi")
qayta_boglash_siz()
print(f"\n Qayta bog'lash (global siz):")
print(f" _KESH={_KESH}, _ROYXAT={_ROYXAT} ⚠️ o'zgarmadi")
qayta_boglash_bilan()
print(f"\n Qayta bog'lash (global bilan):")
print(f" _KESH={_KESH}, _ROYXAT={_ROYXAT} ✅ o'zgardi")
print("""
⭐ Qoida (7.2-dars):
d[k] = v, r.append(x) → OBYEKTNI o'zgartirish → global kerak EMAS
d = {}, r = [] → QAYTA BOG'LASH → global KERAK
""")
print("\n=== 5. Yangi global yaratish ===")
def yangi_yarat():
global yangi_nom
yangi_nom = "yaratildi"
print(f" 'yangi_nom' in globals(): {'yangi_nom' in globals()}")
yangi_yarat()
print(f" yangi_yarat() dan keyin: {'yangi_nom' in globals()}")
print(f" yangi_nom = {yangi_nom!r}")
del globals()["yangi_nom"]
print("\n=== 6. Sintaksis cheklovlari ===")
XATOLAR = [
("Parametr bilan", "def f(x):\n global x\n x = 1"),
("O'zlashtirishdan keyin", "def f():\n x = 1\n global x"),
("lambda da", "f = lambda: global x"),
("nonlocal modulda", "nonlocal x"),
]
for nom, kod in XATOLAR:
try:
exec(compile(kod, "<t>", "exec"))
natija = "✅ ishladi"
except SyntaxError as e:
natija = f"❌ SyntaxError: {e.msg}"
print(f" {nom:<26} {natija}")
print(f"\n ✅ To'g'ri shakllar:")
TOGRI = [
"def f():\n global x\n x = 1",
"def f():\n global a, b, c\n a = b = c = 1",
"def f():\n global x\n return x",
"def f():\n if False:\n global x\n x = 1",
]
for kod in TOGRI:
try:
exec(compile(kod, "<t>", "exec"))
print(f" ✅ {kod.splitlines()[1].strip()}")
except SyntaxError as e:
print(f" ❌ {e.msg}")
print("\n=== 7. ⚠️ Shart ichida ham ta'sir qiladi ===")
def shartli_global():
if False: # ⚠️ hech qachon bajarilmaydi
global shart_test
shart_test = "o'rnatildi" # lekin bu GLOBAL
shartli_global()
print(f" def f():")
print(f" if False:")
print(f" global shart_test")
print(f" shart_test = 'o`rnatildi'\n")
print(f" 'shart_test' in globals(): {'shart_test' in globals()} ⚠️")
print(f" shart_test = {shart_test!r}")
print(f"\n ⭐ Kompilyator butun tanani skanerlaydi — shart ahamiyatsiz")
del globals()["shart_test"]
print("\n=== 8. Ichma-ich funksiyada ===")
def tashqi():
x = "ENCLOSING"
def ichki():
global x # ⭐ MODUL, enclosing emas
x = "GLOBAL_dan_yozildi"
ichki()
return x # ENCLOSING o'zgarmadi
x = "asl global"
natija = tashqi()
print(f" def tashqi():")
print(f" x = 'ENCLOSING'")
print(f" def ichki():")
print(f" global x # ⭐ MODUL darajasi")
print(f" x = '...'")
print(f" return x\n")
print(f" tashqi() qaytardi: {natija!r} (enclosing o'zgarmadi)")
print(f" global x: {x!r} ✅ o'zgardi")Natijaning muhim qismi:
=== 4. ⚠️ O'zgartirish vs qayta bog'lash ===
Obyektni o'zgartirish (global siz):
_KESH={'boshlangich': 1, 'yangi': 2}, _ROYXAT=[1, 2, 3] ✅ o'zgardi
Qayta bog'lash (global siz):
_KESH={'boshlangich': 1, 'yangi': 2}, _ROYXAT=[1, 2, 3] ⚠️ o'zgarmadi
Qayta bog'lash (global bilan):
_KESH={'tozalandi': True}, _ROYXAT=[] ✅ o'zgardi
=== 6. Sintaksis cheklovlari ===
Parametr bilan ❌ SyntaxError: name 'x' is parameter and global
O'zlashtirishdan keyin ❌ SyntaxError: name 'x' is assigned to before
global declaration
lambda da ❌ SyntaxError: invalid syntaxNima ko'rsatdi: 2.1, 2.4, 2.6-bo'limlar.
Misol 2 — nonlocal
"""nonlocal — enclosing qamroviga yozish."""
print("=== 1. Muammo va yechim ===")
def sanagich_yomon():
hisob = 0
def ichki():
hisob += 1 # ⚠️
return hisob
return ichki
def sanagich_yaxshi():
hisob = 0
def ichki():
nonlocal hisob
hisob += 1
return hisob
return ichki
print(f" def sanagich():")
print(f" hisob = 0")
print(f" def ichki():")
print(f" hisob += 1")
print(f" return ichki\n")
f = sanagich_yomon()
try:
f()
except UnboundLocalError as e:
print(f" → ❌ UnboundLocalError: {e}\n")
print(f" nonlocal bilan:")
g = sanagich_yaxshi()
print(f" g() → {g()}, {g()}, {g()} ✅")
print("\n=== 2. ⭐ global vs nonlocal ===")
x = "GLOBAL"
def demo():
x = "ENCLOSING"
def global_bilan():
global x
x = "global_dan"
def nonlocal_bilan():
nonlocal x
x = "nonlocal_dan"
def lokal():
x = "lokal"
return x
natijalar = {}
lokal_natija = lokal()
natijalar["lokal dan keyin enclosing"] = x
nonlocal_bilan()
natijalar["nonlocal dan keyin enclosing"] = x
global_bilan()
natijalar["global dan keyin enclosing"] = x
return natijalar
natijalar = demo()
print(f" Boshida: global x = 'GLOBAL', enclosing x = 'ENCLOSING'\n")
for nom, qiymat in natijalar.items():
print(f" {nom:<34} {qiymat!r}")
print(f" {'Modul darajasidagi x':<34} {x!r}")
print("""
⭐ lokal → hech narsani o'zgartirmadi
nonlocal → ENCLOSING o'zgardi
global → MODUL o'zgardi
""")
print("\n=== 3. Cheklovlar ===")
CHEKLOVLAR = [
("Nom mavjud emas",
"def t():\n def i():\n nonlocal yoq\n yoq = 1\n i()"),
("Modul darajasida",
"nonlocal x"),
("Global ni topish",
"gx = 1\ndef f():\n nonlocal gx\n gx = 2"),
("Parametr bilan",
"def t():\n def i(x):\n nonlocal x\n i(1)"),
]
for nom, kod in CHEKLOVLAR:
try:
exec(compile(kod, "<t>", "exec"))
natija = "✅ ishladi"
except SyntaxError as e:
natija = f"❌ {e.msg}"
print(f" {nom:<22} {natija}")
print(f"\n ✅ To'g'ri: nom enclosing da MAVJUD bo'lishi kerak")
print(f"""
def tashqi():
x = 1 ← mavjud
def ichki():
nonlocal x ✅
x = 2
""")
print("\n=== 4. Eng yaqin enclosing ===")
def a():
x = "a"
def b():
x = "b" # ⭐ eng yaqin
def c():
nonlocal x
x = "c_dan"
c()
return x
b_natija = b()
return b_natija, x
b_natija, a_x = a()
print(f" def a(): x = 'a'")
print(f" def b(): x = 'b'")
print(f" def c(): nonlocal x; x = 'c_dan'\n")
print(f" b() qaytardi: {b_natija!r} ⭐ b ning x i o'zgardi")
print(f" a ning x i: {a_x!r} ✅ o'zgarmadi")
def a2():
x = "a2"
def b2():
def c2():
nonlocal x # ⭐ b2 da x yo'q → a2 niki
x = "c2_dan"
c2()
b2()
return x
print(f"\n def a(): x = 'a2'")
print(f" def b(): (x yo'q)")
print(f" def c(): nonlocal x; x = 'c2_dan'\n")
print(f" a ning x i: {a2()!r} ⭐ eng yaqin MAVJUD x topildi")
print("\n=== 5. Amaliy: dekoratorlarda ===")
from functools import wraps
def sanagich_dekorator(f):
"""nonlocal bilan chaqiruvlarni sanaydi."""
chaqiruvlar = 0
@wraps(f)
def ichki(*args, **kwargs):
nonlocal chaqiruvlar
chaqiruvlar += 1
return f(*args, **kwargs)
ichki.chaqiruvlar = lambda: chaqiruvlar
ichki.tozala = lambda: None # ⚠️ nonlocal ni tashqaridan tozalab bo'lmaydi
return ichki
def kesh_dekorator(f):
"""nonlocal bilan statistika."""
saqlangan = {}
topildi = topilmadi = 0
@wraps(f)
def ichki(*args):
nonlocal topildi, topilmadi
if args in saqlangan:
topildi += 1
return saqlangan[args]
topilmadi += 1
natija = saqlangan[args] = f(*args)
return natija
ichki.statistika = lambda: {
"topildi": topildi,
"topilmadi": topilmadi,
"hajm": len(saqlangan),
}
ichki.tozala = saqlangan.clear
return ichki
@sanagich_dekorator
def salom(ism):
return f"Salom, {ism}!"
@kesh_dekorator
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
for ism in ["Aziz", "Bobur", "Aziza"]:
salom(ism)
print(f" @sanagich_dekorator:")
print(f" 3 chaqiruvdan keyin: {salom.chaqiruvlar()}")
fib(20)
fib(20)
fib(10)
print(f"\n @kesh_dekorator:")
print(f" fib(20), fib(20), fib(10) dan keyin:")
for k, v in fib.statistika().items():
print(f" {k:<12} {v}")
print("""
⚠️ nonlocal bilan holatni tashqaridan TOZALAB bo'lmaydi
(faqat yopilma ichidagi funksiyalar orqali).
⭐ Shuning uchun murakkab holat uchun SINF yaxshiroq.
""")
print("\n=== 6. nonlocal vs sinf ===")
def sanagich_nonlocal(boshlangich=0, qadam=1):
hisob = boshlangich
def keyingi():
nonlocal hisob
hisob += qadam
return hisob
def tozala():
nonlocal hisob
hisob = boshlangich
def joriy():
return hisob
keyingi.tozala = tozala
keyingi.joriy = joriy
return keyingi
class SanagichSinf:
def __init__(self, boshlangich=0, qadam=1):
self._boshlangich = boshlangich
self.qadam = qadam
self.hisob = boshlangich
def __call__(self):
self.hisob += self.qadam
return self.hisob
def tozala(self):
self.hisob = self._boshlangich
def __repr__(self):
return f"Sanagich(hisob={self.hisob}, qadam={self.qadam})"
n = sanagich_nonlocal(0, 5)
s = SanagichSinf(0, 5)
print(f" {'Amal':<20} {'nonlocal':<14} {'sinf'}")
print(" " + "─" * 46)
for i in range(3):
print(f" {'chaqirish':<20} {n():<14} {s()}")
print(f" {'joriy holat':<20} {n.joriy():<14} {s.hisob}")
n.tozala()
s.tozala()
print(f" {'tozalashdan keyin':<20} {n.joriy():<14} {s.hisob}")
print(f"\n Sinf afzalliklari:")
print(f" • repr: {s!r}")
print(f" • Atributga to'g'ridan-to'g'ri: s.hisob = 100")
s.hisob = 100
print(f" → {s.hisob}")
print(f" • qadam ni o'zgartirish: s.qadam = 10")
s.qadam = 10
print(f" → {s()}")
print(f" • Meros, xususiyatlar, metodlar")
print("""
⭐ nonlocal — KICHIK, mahalliy holat uchun (dekoratorlar)
Sinf — murakkab holat, ko'p metod, meros uchun
""")Natijaning muhim qismi:
=== 2. ⭐ global vs nonlocal ===
lokal dan keyin enclosing 'ENCLOSING'
nonlocal dan keyin enclosing 'nonlocal_dan'
global dan keyin enclosing 'nonlocal_dan'
Modul darajasidagi x 'global_dan'
=== 3. Cheklovlar ===
Nom mavjud emas ❌ no binding for nonlocal 'yoq' found
Modul darajasida ❌ nonlocal declaration not allowed at module level
Global ni topish ❌ no binding for nonlocal 'gx' found
=== 4. Eng yaqin enclosing ===
b() qaytardi: 'c_dan' ⭐ b ning x i o'zgardi
a ning x i: 'a' ✅ o'zgarmadiNima ko'rsatdi: 2.2, 2.3-bo'limlar.
Misol 3 — Muqobillar va ko'p oqim
"""Global holatdan qochish usullari."""
import threading
import time
from dataclasses import dataclass, field
from itertools import count
from functools import lru_cache
print("=== 1. Global holat muammolari ===")
jami = 0
def qosh_global(x):
global jami
jami += x
return jami
print(f" ❌ Global holat:\n")
print(f" qosh(1) = {qosh_global(1)}")
print(f" qosh(2) = {qosh_global(2)}")
print(f" qosh(3) = {qosh_global(3)}")
print(f"""
Muammolar:
1. Test qilish qiyin — har testdan oldin `jami = 0` kerak
2. Ikkita mustaqil hisoblagich yaratib bo'lmaydi
3. Ko'p oqimda xavfli
4. Funksiya imzosida bog'liqlik ko'rinmaydi
5. Kim o'zgartirdi — kuzatish qiyin
""")
jami = 0
print("=== 2. To'rt muqobil ===\n")
# 1. Toza funksiya
def qosh_toza(jami, x):
return jami + x
# 2. Sinf
class Hisoblagich:
def __init__(self, boshlangich=0):
self.jami = boshlangich
def qosh(self, x):
self.jami += x
return self.jami
def tozala(self):
self.jami = 0
return self
# 3. Yopilma
def hisoblagich_yarat(boshlangich=0):
jami = boshlangich
def qosh(x):
nonlocal jami
jami += x
return jami
qosh.joriy = lambda: jami
return qosh
# 4. dataclass
@dataclass
class Holat:
jami: int = 0
tarix: list = field(default_factory=list)
def qosh(self, x):
self.jami += x
self.tarix.append(x)
return self.jami
print(f" 1. Toza funksiya:")
j = 0
for x in [1, 2, 3]:
j = qosh_toza(j, x)
print(f" j = qosh(j, {x}) → {j}")
print(f"\n 2. Sinf:")
h = Hisoblagich()
for x in [1, 2, 3]:
print(f" h.qosh({x}) → {h.qosh(x)}")
print(f"\n 3. Yopilma:")
q = hisoblagich_yarat()
for x in [1, 2, 3]:
print(f" q({x}) → {q(x)}")
print(f"\n 4. dataclass:")
d = Holat()
for x in [1, 2, 3]:
print(f" d.qosh({x}) → {d.qosh(x)}")
print(f" Tarix: {d.tarix}")
print(f"\n ⭐ Ikkita mustaqil hisoblagich:")
h1, h2 = Hisoblagich(), Hisoblagich(100)
h1.qosh(5)
h2.qosh(5)
print(f" h1.jami = {h1.jami}, h2.jami = {h2.jami} ✅")
print(f" Global bilan bu MUMKIN EMAS")
print("\n\n=== 3. Tayyor vositalar ===\n")
print(f" itertools.count — hisoblagich:")
sanagich = count(1)
print(f" next(c) = {next(sanagich)}, {next(sanagich)}, {next(sanagich)}")
sanagich2 = count(0, 10)
print(f" count(0, 10): {[next(sanagich2) for _ in range(4)]}")
print(f"\n functools.lru_cache — kesh:")
@lru_cache(maxsize=128)
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
fib(30)
print(f" fib(30) = {fib(30):,}")
print(f" {fib.cache_info()}")
fib.cache_clear()
print(f" cache_clear() dan keyin: {fib.cache_info()}")
print(f"\n Funksiya atributi:")
def sanagich_atribut():
sanagich_atribut.hisob += 1
return sanagich_atribut.hisob
sanagich_atribut.hisob = 0
print(f" f() = {sanagich_atribut()}, {sanagich_atribut()}, {sanagich_atribut()}")
print(f" f.hisob = {sanagich_atribut.hisob}")
print("\n\n=== 4. ⚠️ Ko'p oqim va poyga holati ===\n")
N = 2_000
OQIMLAR = 4
sanoq_global = 0
def qosh_qulfsiz():
global sanoq_global
for _ in range(N):
joriy = sanoq_global # 1. o'qish
time.sleep(0) # ⚠️ real kodda: I/O, chaqiruv...
sanoq_global = joriy + 1 # 2. yozish (eski qiymat asosida!)
qulf = threading.Lock()
sanoq_qulfli = 0
def qosh_qulfli():
global sanoq_qulfli
for _ in range(N):
with qulf: # ⭐ o'qish+yozish bitta blokda
joriy = sanoq_qulfli
time.sleep(0)
sanoq_qulfli = joriy + 1
def qosh_lokal(n):
"""✅ Global holatsiz."""
return sum(1 for _ in range(n))
KUTILGAN = N * OQIMLAR
# Qulfsiz
boshlandi = time.perf_counter()
oqimlar = [threading.Thread(target=qosh_qulfsiz) for _ in range(OQIMLAR)]
for o in oqimlar: o.start()
for o in oqimlar: o.join()
vaqt_qulfsiz = time.perf_counter() - boshlandi
# Qulfli
boshlandi = time.perf_counter()
oqimlar = [threading.Thread(target=qosh_qulfli) for _ in range(OQIMLAR)]
for o in oqimlar: o.start()
for o in oqimlar: o.join()
vaqt_qulfli = time.perf_counter() - boshlandi
# Lokal
from concurrent.futures import ThreadPoolExecutor
boshlandi = time.perf_counter()
with ThreadPoolExecutor(OQIMLAR) as pool:
natijalar = list(pool.map(qosh_lokal, [N] * OQIMLAR))
sanoq_lokal = sum(natijalar)
vaqt_lokal = time.perf_counter() - boshlandi
print(f" {OQIMLAR} oqim × {N:,} increment (kutilgan: {KUTILGAN:,}):\n")
print(f" {'Usul':<24} {'Natija':>12} {'To`g`rimi':>10} {'Vaqt':>10}")
print(" " + "─" * 60)
for nom, natija, vaqt in [
("global (qulfsiz)", sanoq_global, vaqt_qulfsiz),
("global + Lock", sanoq_qulfli, vaqt_qulfli),
("lokal (global holatsiz)", sanoq_lokal, vaqt_lokal),
]:
belgi = "✅" if natija == KUTILGAN else "❌"
print(f" {nom:<24} {natija:>12,} {belgi:>9} {vaqt * 1000:>8.0f} ms")
print(f"\n Sabab — `sanoq += 1` bir nechta instruksiya (o'qish → qo'shish → yozish):")
import dis
def increment():
global sanoq_global
sanoq_global += 1
ins = []
for i in dis.get_instructions(increment):
if i.opname.startswith("RETURN"):
break
if i.opname != "RESUME":
ins.append(i.opname)
if ins and ins[-1] == "LOAD_CONST": # yashirin "return None"
ins.pop()
print(f" {ins}")
print(f" ⚠️ Oqim ular ORASIDA uzilishi mumkin — GIL buni kafolatlamaydi")
print(f" ⭐ Oddiy `+=` da CPython amalda kamdan-kam uziladi, shuning uchun")
print(f" yuqorida o'qish va yozish orasiga sleep(0) qo'yib, oynani ochdik.")
print(f" Real kodda bu oynani I/O yoki funksiya chaqiruvi ochadi.")
print("\n\n=== 5. threading.local ===\n")
lokal_malumot = threading.local()
def oqim_ishi(nom):
lokal_malumot.nom = nom
lokal_malumot.hisob = 0
for _ in range(1000):
lokal_malumot.hisob += 1 # ✅ har oqimga o'z nusxasi
return f"{lokal_malumot.nom}: {lokal_malumot.hisob}"
with ThreadPoolExecutor(3) as pool:
natijalar = list(pool.map(oqim_ishi, ["A", "B", "C"]))
print(f" threading.local() bilan:")
for n in natijalar:
print(f" {n} ✅ har oqim mustaqil")
print(f"\n Asosiy oqimda:")
print(f" hasattr(lokal_malumot, 'nom'): "
f"{hasattr(lokal_malumot, 'nom')} ⭐ o'z nusxasi")
print("\n\n=== 6. contextvars (async uchun) ===\n")
from contextvars import ContextVar, copy_context
joriy_foydalanuvchi: ContextVar[str] = ContextVar("foydalanuvchi",
default="mehmon")
def kim():
return joriy_foydalanuvchi.get()
def ish_bajar(ism):
token = joriy_foydalanuvchi.set(ism)
try:
return f"{kim()} ish bajarmoqda"
finally:
joriy_foydalanuvchi.reset(token)
print(f" Boshida: {kim()!r}")
print(f" {ish_bajar('aziz')}")
print(f" Keyin: {kim()!r} ✅ tiklandi")
print(f"\n Alohida kontekstda:")
kontekst = copy_context()
kontekst.run(joriy_foydalanuvchi.set, "bobur")
print(f" Kontekst ichida: {kontekst.run(kim)!r}")
print(f" Tashqarida: {kim()!r} ✅ ta'sir qilmadi")
print("""
⭐ contextvars — async va oqimlar uchun "global" holat:
• Har kontekst (task/thread) o'z qiymatini ko'radi
• Web freymvorklarida so'rov konteksti uchun ishlatiladi
""")
print("\n=== 7. Qaror jadvali ===\n")
print("""
┌────────────────────────────┬──────────────────────────────────┐
│ Ehtiyoj │ Yechim │
├────────────────────────────┼──────────────────────────────────┤
│ Hisoblash natijasi │ return ⭐ (toza funksiya) │
│ Murakkab holat + metodlar │ Sinf ⭐ │
│ Kichik holat (dekorator) │ nonlocal │
│ Hisoblagich │ itertools.count │
│ Kesh │ functools.lru_cache │
│ Modul singleton'i │ global (kirish funksiyasi bilan) │
│ Oqimga bog'liq holat │ threading.local │
│ Async kontekst │ contextvars │
│ Ko'p oqim + umumiy holat │ Lock, Queue, yoki holatsiz ⭐ │
│ Konfiguratsiya │ frozen dataclass / modul │
└────────────────────────────┴──────────────────────────────────┘
""")Natijaning muhim qismi:
=== 4. ⚠️ Ko'p oqim va poyga holati ===
4 oqim × 2,000 increment (kutilgan: 8,000):
Usul Natija To`g`rimi Vaqt
────────────────────────────────────────────────────────────
global (qulfsiz) 2,516 ❌ 8 ms
global + Lock 8,000 ✅ 33 ms
lokal (global holatsiz) 8,000 ✅ 1 ms
Sabab — `sanoq += 1` bir nechta instruksiya (o'qish → qo'shish → yozish):
['LOAD_GLOBAL', 'LOAD_SMALL_INT', 'BINARY_OP', 'STORE_GLOBAL']
⚠️ Oqim ular ORASIDA uzilishi mumkin — GIL buni kafolatlamaydi
=== 5. threading.local ===
A: 1000 ✅ har oqim mustaqil
B: 1000 ✅ har oqim mustaqil
C: 1000 ✅ har oqim mustaqilNima ko'rsatdi: 2.3, 2.5, 2.7-bo'limlar.
Misol 4 — Amaliy: modul holati va refaktoring
"""Global holatni to'g'ri boshqarish va undan qochish."""
import sys
import threading
import time
from dataclasses import dataclass, field
from typing import Any
print("=== 1. Modul singleton naqshi ===\n")
# ─── "Modul" simulyatsiyasi ───
_ULANISH: Any = None
_ULANISHLAR_SONI = 0
_KESH: dict[str, Any] = {}
_QULF = threading.Lock()
def _ulan():
"""Qimmat resurs yaratish."""
global _ULANISHLAR_SONI
_ULANISHLAR_SONI += 1
time.sleep(0.001)
return f"<ulanish#{_ULANISHLAR_SONI}>"
def ulanish_ol():
"""⭐ Singleton — bir marta yaratiladi."""
global _ULANISH
if _ULANISH is None:
with _QULF:
if _ULANISH is None: # ⭐ ikki marta tekshirish
_ULANISH = _ulan()
return _ULANISH
def ulanishni_yop():
"""Resursni bo'shatish."""
global _ULANISH
if _ULANISH is not None:
_ULANISH = None
def keshdan_ol(kalit, yaratuvchi):
"""Kesh — global KERAK EMAS (obyektni o'zgartirish)."""
if kalit not in _KESH:
_KESH[kalit] = yaratuvchi()
return _KESH[kalit]
def keshni_tozala():
"""✅ global kerak emas — clear() obyektni o'zgartiradi."""
_KESH.clear()
print(f" Singleton ulanish:")
for i in range(3):
print(f" ulanish_ol() → {ulanish_ol()}")
print(f" Yaratilgan ulanishlar: {_ULANISHLAR_SONI} ⭐ bitta")
ulanishni_yop()
print(f"\n Yopilgandan keyin:")
print(f" ulanish_ol() → {ulanish_ol()} (yangi yaratildi)")
print(f"\n Kesh:")
for kalit in ["a", "b", "a"]:
qiymat = keshdan_ol(kalit, lambda: f"qiymat_{kalit}_{time.time():.6f}")
print(f" keshdan_ol({kalit!r}) → {qiymat}")
print(f" Kesh hajmi: {len(_KESH)}")
keshni_tozala()
print(f" Tozalangandan keyin: {len(_KESH)}")
print("""
⭐ Modul holati uchun qoidalar:
1. Nom `_` bilan boshlansin (xususiy)
2. Kirish faqat funksiyalar orqali
3. Ko'p oqim uchun Lock
4. Tozalash funksiyasi bo'lsin (test uchun)
""")
print("\n=== 2. ⚠️ from import muammosi ===\n")
# Ikki modulni simulyatsiya qilish
MODUL_A = """
x = 1
def ozgartir():
global x
x = 2
def ol():
return x
"""
import types
a_modul = types.ModuleType("a_modul")
exec(MODUL_A, a_modul.__dict__)
sys.modules["a_modul"] = a_modul
# b.py: from a import x
from a_modul import x as import_qilingan_x, ozgartir, ol
import a_modul
print(f" # a.py: x = 1")
print(f" # b.py: from a import x, ozgartir")
print(f" import a\n")
print(f" Boshida:")
print(f" import_qilingan_x = {import_qilingan_x}")
print(f" a_modul.x = {a_modul.x}")
ozgartir()
print(f"\n ozgartir() dan keyin:")
print(f" import_qilingan_x = {import_qilingan_x} ⚠️ o'zgarmadi!")
print(f" a_modul.x = {a_modul.x} ✅")
print(f" ol() = {ol()} ✅ (modul ichidan)")
print("""
⭐ `from a import x` — x ning JORIY qiymatiga yangi nom bog'laydi.
Keyingi o'zgarishlar ko'rinmaydi.
✅ O'zgaruvchan global holat uchun:
import modul
modul.x
""")
del sys.modules["a_modul"]
print("\n=== 3. Refaktoring: global → sinf ===\n")
print(f" ❌ ASL (global holat bilan):\n")
print(""" _sozlamalar = {}
_tarix = []
_joriy_foydalanuvchi = None
def kirish(ism):
global _joriy_foydalanuvchi
_joriy_foydalanuvchi = ism
_tarix.append(("kirish", ism))
def sozla(kalit, qiymat):
if _joriy_foydalanuvchi is None:
raise RuntimeError("avval kiring")
_sozlamalar[kalit] = qiymat
_tarix.append(("sozla", kalit, qiymat))
def chiqish():
global _joriy_foydalanuvchi
_tarix.append(("chiqish", _joriy_foydalanuvchi))
_joriy_foydalanuvchi = None
""")
@dataclass
class Sessiya:
"""✅ REFAKTORING: holat obyektda."""
sozlamalar: dict[str, Any] = field(default_factory=dict)
tarix: list[tuple] = field(default_factory=list)
joriy_foydalanuvchi: str | None = None
def kirish(self, ism: str) -> "Sessiya":
self.joriy_foydalanuvchi = ism
self.tarix.append(("kirish", ism))
return self
def sozla(self, kalit: str, qiymat: Any) -> "Sessiya":
if self.joriy_foydalanuvchi is None:
raise RuntimeError("avval kiring")
self.sozlamalar[kalit] = qiymat
self.tarix.append(("sozla", kalit, qiymat))
return self
def chiqish(self) -> "Sessiya":
self.tarix.append(("chiqish", self.joriy_foydalanuvchi))
self.joriy_foydalanuvchi = None
return self
def hisobot(self) -> str:
qatorlar = [f"Foydalanuvchi: {self.joriy_foydalanuvchi or '(kirmagan)'}"]
qatorlar.append(f"Sozlamalar: {self.sozlamalar}")
qatorlar.append(f"Tarix ({len(self.tarix)} amal):")
for amal in self.tarix:
qatorlar.append(f" • {' '.join(map(str, amal))}")
return "\n".join(qatorlar)
print(f" ✅ Sinf bilan:\n")
s = Sessiya()
s.kirish("aziz").sozla("til", "uz").sozla("tema", "qora").chiqish()
for q in s.hisobot().splitlines():
print(f" {q}")
print(f"\n ⭐ Afzalliklar:\n")
s1 = Sessiya().kirish("aziz").sozla("til", "uz")
s2 = Sessiya().kirish("bobur").sozla("til", "en")
print(f" 1. Ikki mustaqil sessiya:")
print(f" s1: {s1.joriy_foydalanuvchi}, til={s1.sozlamalar['til']}")
print(f" s2: {s2.joriy_foydalanuvchi}, til={s2.sozlamalar['til']}")
print(f"\n 2. Test oson — har testda yangi obyekt")
print(f" 3. Zanjirlash: s.kirish().sozla().chiqish()")
print(f" 4. Ko'p oqim: har oqimga o'z Sessiya()")
print(f" 5. Holat repr da ko'rinadi")
try:
Sessiya().sozla("x", 1)
except RuntimeError as e:
print(f"\n 6. Validatsiya ishlaydi: ❌ {e}")
print("\n\n=== 4. Qachon global maqbul ===\n")
print(""" ✅ Maqbul holatlar:
1. Modul konstantalari (o'zgarmas)
MAKSIMAL_URINISH = 3
RUXSAT_ETILGAN = frozenset({...})
2. Singleton resurs (kirish funksiyasi bilan)
def ulanish_ol():
global _ULANISH
if _ULANISH is None: ...
3. Kesh (ichki, xususiy)
_KESH = {} # global kerak emas — o'zgartirish
4. Ro'yxatga olish (registry)
_HANDLERLAR = {}
def royxatga_ol(nom): ...
5. Kichik skript / prototip
❌ Nomaqbul:
1. Ilova holati (foydalanuvchi, sessiya, ma'lumot)
2. Hisoblash natijalarini yig'ish
3. Funksiyalar orasida ma'lumot uzatish
4. Ko'p oqimli kod (Lock siz)
5. Kutubxona ichida (foydalanuvchi kutmaydi)
""")
print("=== 5. Global holat testlari ===\n")
_TEST_HOLAT = {"sanoq": 0}
def global_bilan_funksiya():
_TEST_HOLAT["sanoq"] += 1
return _TEST_HOLAT["sanoq"]
def toza_funksiya(sanoq):
return sanoq + 1
print(f" Global holat bilan test:")
print(f"""
def test_1():
_TEST_HOLAT["sanoq"] = 0 # ⚠️ tiklash KERAK
assert global_bilan_funksiya() == 1
def test_2():
_TEST_HOLAT["sanoq"] = 0 # ⚠️ yana
assert global_bilan_funksiya() == 1
""")
print(f" Test tartibiga bog'liqlik:")
_TEST_HOLAT["sanoq"] = 0
n1 = global_bilan_funksiya()
n2 = global_bilan_funksiya()
print(f" Ketma-ket: {n1}, {n2} ⚠️ ikkinchi test 1 kutgan bo'lardi")
print(f"\n Toza funksiya bilan:")
print(f"""
def test_1():
assert toza_funksiya(0) == 1 ✅ tiklash kerak emas
def test_2():
assert toza_funksiya(0) == 1 ✅ mustaqil
""")
print(f" toza_funksiya(0) = {toza_funksiya(0)}, "
f"{toza_funksiya(0)} ✅ har doim bir xil")
print("""
⭐ pytest fixture bilan global holatni tiklash:
@pytest.fixture(autouse=True)
def holatni_tikla():
_TEST_HOLAT["sanoq"] = 0
yield
_TEST_HOLAT.clear()
Lekin eng yaxshisi — global holatdan voz kechish.
""")
print("=== 6. Yakuniy tavsiyalar ===\n")
print("""
1️⃣ Birinchi savol: "Global holat kerakmi?"
Ko'p holatda javob — YO'Q.
2️⃣ Agar kerak bo'lsa, tartib bo'yicha:
• return (toza funksiya) ⭐
• Sinf / dataclass
• Yopilma + nonlocal
• Modul + kirish funksiyalari
• global (oxirgi chora)
3️⃣ global ishlatsangiz:
• Nom `_` bilan (xususiy)
• Faqat funksiyalar orqali kirish
• Ko'p oqimda Lock
• Tozalash funksiyasi (test uchun)
• Hujjatda yozing
4️⃣ nonlocal ishlatsangiz:
• Faqat kichik, mahalliy holat
• Dekoratorlar uchun ideal
• Murakkablashsa — sinfga o'ting
""")Natijaning muhim qismi:
=== 1. Modul singleton naqshi ===
Singleton ulanish:
ulanish_ol() → <ulanish#1>
ulanish_ol() → <ulanish#1>
ulanish_ol() → <ulanish#1>
Yaratilgan ulanishlar: 1 ⭐ bitta
=== 2. ⚠️ from import muammosi ===
ozgartir() dan keyin:
import_qilingan_x = 1 ⚠️ o'zgarmadi!
a_modul.x = 2 ✅
=== 3. Refaktoring: global → sinf ===
1. Ikki mustaqil sessiya:
s1: aziz, til=uz
s2: bobur, til=enNima ko'rsatdi: 2.3, 2.4, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"O'qish uchun global kerak" |
Faqat yozish uchun |
"d[k] = v uchun global kerak" |
Obyektni o'zgartirish — kerak emas |
"nonlocal global ni topadi" |
SyntaxError |
"nonlocal yangi nom yaratadi" |
Nom mavjud bo'lishi shart |
"global faqat funksiya boshida" |
Istalgan joyda, lekin ishlatishdan oldin |
| "GIL global holatni himoya qiladi" | += — bir nechta instruksiya; GIL ular orasida uzilmaslikni kafolatlamaydi |
"from a import x havola beradi" |
Nusxa — keyingi o'zgarish ko'rinmaydi |
"global shart ichida ta'sir qilmaydi" |
Kompilyator butun tanani ko'radi |
| "Yopilma holati — global kabi yomon" | Mahalliy va nazorat ostida |
6. Keng tarqalgan xatolar va yechimlari
1. global unutish
sanoq = 0
def f():
sanoq += 1 # ❌ UnboundLocalError
global sanoq # ✅ (birinchi qatorga)2. Ortiqcha global
def f():
global x
return x # ⚠️ o'qish uchun kerak emas3. nonlocal mavjud bo'lmagan nom uchun
def t():
def i():
nonlocal x # ❌ SyntaxError
x = 14. nonlocal global uchun
x = 1
def f():
nonlocal x # ❌ SyntaxError
global x # ✅5. from import bilan o'zgaruvchan global
from modul import sanoq # ⚠️ nusxa
import modul; modul.sanoq # ✅6. Ko'p oqimda qulfsiz
def f():
global sanoq
sanoq += 1 # ⚠️ race condition
with qulf: # ✅
sanoq += 17. Global holat testda
def test():
assert f() == 1 # ⚠️ oldingi testga bog'liq
@pytest.fixture(autouse=True) # ✅
def tikla(): _HOLAT.clear()8. Kutubxonada global holat
# kutubxona.py
_natija = None # ⚠️ foydalanuvchi kutmaydi
class Ishlov: # ✅
def __init__(self): self.natija = None7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 7.8-dars (o'tilgan): LEGB,
UnboundLocalError - 7.2-dars (o'tilgan): o'zgartirish vs qayta bog'lash
- 8-qism: sinflar — holatning to'g'ri joyi
- 10-qism: dekoratorlar (
nonlocalbilan) - 19-qism: modullar,
importsemantikasi - 14-qism: ko'p oqim,
threading,asyncio,contextvars - 17-qism: testlash, fixture, izolyatsiya
8. Eng yaxshi amaliyotlar
Global holatdan qoching. Qaytarish, sinf yoki yopilma ishlating.
global— faqat yozish uchun. O'qish uchun kerak emas.Obyektni o'zgartirish uchun
globalkerak emas._KESH[k] = v.Global nomlar
_bilan. Kirish faqat funksiyalar orqali.nonlocal— kichik, mahalliy holat uchun. Dekoratorlarda ideal.O'zgaruvchan global uchun
import modul.from modul import x— nusxa.Ko'p oqimda
Lockyoki holatsiz dizayn. GIL yetarli emas.Global holat bo'lsa — tozalash funksiyasi yozing. Testlar uchun.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
x = 1
d = {}
1. def f(): return x
print(f())
2. def f(): x = 2
f(); print(x)
3. def f():
global x
x = 2
f(); print(x)
4. def f(): d["a"] = 1
f(); print(d)
5. def f(): d = {}
f(); print(d)
6. def f():
print(x); x = 2
f()
7. def t():
y = 1
def i(): nonlocal y; y = 2
i(); return y
print(t())
8. def t():
def i(): nonlocal z; z = 1
i()
9. def f():
global gz
gz = 1
f(); print(gz)
10. def f():
if False: global w
w = 1
f(); print(w)
11. def t():
a = 1
def i(): a = 2
i(); return a
print(t())
12. def f(p):
global pJavoblar
11— lokal2{'a': 1}— obyektni o'zgartirish{'a': 1}— qayta bog'lash lokal-
UnboundLocalError 2-
SyntaxError—zmavjud emas 1— yangi global yaratildi1— shart ahamiyatsiz1— ichkiaalohida-
SyntaxError— parametr va global
Vazifa 2: Xatolarni tuzating
1. sanoq = 0
def qosh(): sanoq += 1
2. def t():
h = 0
def i(): h += 1
return i
3. x = 1
def f():
nonlocal x
x = 2
4. from modul import sanoq
modul.oshir(); print(sanoq)
5. def f():
global sanoq
sanoq += 1 # ko'p oqimda
6. _KESH = {}
def f():
global _KESH
_KESH["a"] = 1
7. def f():
x = 1
global x
8. jami = 0
def qosh(x):
global jami
jami += x
# test yozish kerakJavoblar
1. def qosh(): global sanoq; sanoq += 1
2. def i(): nonlocal h; h += 1
3. global x (nonlocal emas)
4. import modul; modul.oshir(); print(modul.sanoq)
5. with qulf: sanoq += 1 (yoki holatsiz dizayn)
6. global kerak emas — obyektni o'zgartirish
7. global x ni birinchi qatorga
8. Sinfga o'tkazing yoki def qosh(jami, x): return jami + xVazifa 3: Refaktoring
Global holatli kodni uch xil qayta yozing:
_foydalanuvchi = None
_sozlamalar = {}
_tarix = []
def kirish(ism): ...
def sozla(k, v): ...
def chiqish(): ...
def tarix_ol(): ...- Toza funksiyalar (holat argument sifatida)
- Sinf
- Yopilma +
nonlocal - Har biri uchun testlar
- Ikki mustaqil sessiya yaratib ko'ring
- Qaysi biri qachon yaxshiroq — tahlil
Vazifa 4: Holat vositalari
Yozing:
Sanagich—__call__,tozala,qadam, kontekst menejeriKesh—maxsize,ttl, statistikaRegistr—royxatga_oldekoratori,chaqir,royxatSessiya— kirish/chiqish, tarix,withbilan- Har biri global holatsiz bo'lsin
- Ko'p oqimga xavfsiz variantlarini ham
Vazifa 5: Poyga holati tadqiqoti
Dastur yozing:
+=ning atomik emasligini ko'rsating- Turli oqim soni va iteratsiyada xatoni o'lchang
- Yechimlar:
Lock,RLock,atomic(itertools.count) - Har birining tezligini solishtiring
threading.localvacontextvarsbilan- GIL nimani himoya qiladi, nimani yo'q
Vazifa 6: Modul holati auditi
Vosita yozing:
- Modul darajasidagi o'zgaruvchan obyektlarni topsin (
ast) - Qaysi funksiyalar
globalishlatishini from x import ybilan import qilingan o'zgaruvchan nomlarni- Ko'p oqim xavfini baholasin
- Refaktoring taklifini bersin
- Hisobot chiqarsin
Vazifa 7: O'ylash
Nega Python global va nonlocal ni e'lon qildi, boshqa tillar kabi $global yoki outer.x sintaksisi o'rniga?
Javob
Chunki e'lon kompilyatsiya paytida ishlaydi va o'qilishi aniq.
Muqobil dizaynlar:
1. Prefiks (PHP, Perl):
$GLOBALS['x'] = 1; // PHPour $x = 1; # PerlMuammo: har murojaatda prefiks yozish kerak. Kod shovqinli.
2. Qamrov ko'rsatkichi (hipotetik):
outer.x = 1 # enclosing
module.x = 1 # globalMuammolar:
outervamodule— yangi kalit so'zlar- Ular obyektmi yoki sintaksismi?
- Ichma-ich uch daraja bo'lsa:
outer.outer.x? - Mavjud kod bilan to'qnashuv (
outer— oddiy nom bo'lishi mumkin)
3. Aniq e'lon (JavaScript var/let):
function f() {
let x = 1; // lokal
y = 2; // ⚠️ global (aniq e'lon YO'Q)
}Muammo: teskari — e'lonsiz nom global bo'lib qoladi. Bu — JavaScript ning eng ko'p tanqid qilingan xatolaridan biri ("use strict" bilan tuzatilgan).
4. Python tanlagan: e'lon
def f():
global x
x = 1Afzalliklari:
a) Kompilyatsiya paytida ishlaydi.
Kompilyator butun funksiya tanasini skanerlaydi. global x ko'rsa, barcha x uchun STORE_GLOBAL/LOAD_GLOBAL beradi. Ish vaqtida qo'shimcha tekshiruv yo'q.
b) Sukut — lokal (xavfsiz).
def f():
x = 1 # lokal — tasodifan global o'zgartirilmaydiBu — JavaScript var dan ancha xavfsizroq. Tasodifan global yaratish mumkin emas.
c) Niyat funksiya boshida ko'rinadi.
def f():
global sanoq, kesh # ⭐ darhol ko'rinadi
...O'quvchi funksiyaning global holatga tegishini birinchi qatorlarda biladi.
d) Kam yoziladi.
E'lon bir marta, ishlatish ko'p marta:
def f():
global x
x += 1
x *= 2
return x # har safar prefiks kerak emase) Grep qilish oson.
grep -n "global " *.py # barcha global yozuvlarni topadif) Linterlar tekshiradi.
pylint W0603: global-statement
ruff PLW0603Global ishlatish darhol ko'rinadi va ogohlantiriladi.
Kamchiliklar:
a) E'lon va ishlatish ajralgan:
def f():
global x
# ... 50 qator ...
x = 1 # ⚠️ global ekanini eslash kerakLekin bu — uzun funksiya muammosi, global ning emas.
b) nonlocal cheklovi:
def t():
def i():
nonlocal x # ❌ x mavjud emas
x = 1Yangi nom yaratib bo'lmaydi. Bu — ataylab: nonlocal "mavjud nomni o'zgartirish" degani.
c) Ikkita kalit so'z:
global va nonlocal — o'rganish kerak. Lekin ular kam ishlatiladi.
Tarixiy nozik:
nonlocal faqat Python 3.0 da qo'shildi (PEP 3104, 2006). Undan oldin yopilma o'zgaruvchisini o'zgartirish uchun hiyla kerak edi:
def sanagich():
hisob = [0] # ⚠️ ro'yxat hiylasi
def ichki():
hisob[0] += 1
return hisob[0]
return ichkiPEP 3104 muhokamasida muqobil sintaksislar ko'rilgan:
.x = 1 # nuqta prefiksi
:= # o'shanda walrus uchun emas edi
outer x # kalit so'z
global x in f # murakkabnonlocal tanlandi — chunki u global bilan simmetrik va o'qilishi aniq.
Boshqa tillar:
| Til | Enclosing o'zgartirish |
|---|---|
| Python | nonlocal x |
| JavaScript | Avtomatik (closure) |
| Ruby | Avtomatik (block) |
| Swift | Avtomatik (closure) |
| C++ | [&x] (lambda capture) |
| Rust | move yoki &mut |
Qiziq: ko'p til yopilmani avtomatik o'zgartiruvchan qiladi. Python esa aniq e'lon talab qiladi.
Sabab — Pythonda o'zlashtirish nomni lokal qiladi. Bu qoida barcha qamrov uchun bir xil. nonlocal — bu qoidadan aniq istisno.
Xulosa: e'lon yondashuvi Pythonning ikki tamoyiliga mos:
- "Aniq yashirinlikdan yaxshi" — global o'zgartirish ko'rinadi
- "Sukut xavfsiz bo'lsin" — tasodifan global yaratib bo'lmaydi
Va u kompilyatsiya paytida ishlaydi — tezlik uchun ham foydali.
Nimani mustahkamlaydi: 2.1, 2.2, 2.3-bo'limlar.
Xulosa
Bu darsda global va nonlocal ni o'rgandik.
Eng muhim uch fikr:
global— modul qamroviga,nonlocal— enclosing qamroviga yozish. Ikkalasi ham faqat yozish uchun kerak — o'qish uchun emas. Vanonlocalda nom mavjud bo'lishi shart,globalesa yangisini yaratadi.Obyektni o'zgartirish uchun
globalkerak emas._KESH["a"] = 1— ,_KESH = {}—globalkerak. Bu 7.2-darsdagi "o'zgartirish vs qayta bog'lash" farqi.Global holat — oxirgi chora. Test qilish qiyin, ko'p oqimda xavfli, bog'liqlik yashirin. Muqobillar tartibi: qaytarish (toza funksiya) → sinf → yopilma +
nonlocal→ modul singleton'i →global.
Keyingi darsda lambda ni ko'ramiz: anonim funksiyalar, ularning cheklovlari va qachon oddiy def yaxshiroq.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!