Leksiya 4

Pythonda OOP

Klasslar, obyektlar, vorislik

Masalaning qo'yilishi

Siz Maynkraftni ishga tushirasiz

Sizning personajingiz - Steve.
Uning: ismi, sog'lig'i, xaritadagi koordinatalari, inventari bor.

Buni qanday dasturlash mumkin?

Birinchi urinish

O'zgaruvchilar orqali yondashuv

player_name = "Steve" player_hp = 20 player_x = 0 player_y = 64

Bitta o'yinchi - juda yaxshi ishlaydi.

Agar ular 1000 ta bo'lsa-chi?

Yondashuvni masshtablash

p1_name, p1_hp, p1_x = "Steve", 20, 0 p2_name, p2_hp, p2_x = "Alex", 20, 5 p3_name, p3_hp, p3_x = ... # ... yana 997 qator ...

Bundan tashqari atrofda moblar bor. Va qishloqlar. Va hayvonlar. Nimadir noto'g'ri ketdi.

Yaxshiroq, lekin ideal emas

Lug'atlar orqali yondashuv

p1 = {"name": "Steve", "hp": 20, "x": 0} p2 = {"name": "Alex", "hp": 20, "x": 5}

Allaqachon yaxshiroq. Lekin o'yinchi yurishi, bloklarni buzishi, ovqat yeyishi kerak.

Har safar - lug'atni qabul qiladigan alohida funksiya. Agar kimdir "noto'g'ri" lug'atni uzatsa-chi?

Klass va obyekt

OOP g'oyasi

Dasturchilar - dangasa odamlar.
Ular o'ylab topishdi: keling, o'yinchi ma'lumotlari va u nima qila olishini bitta qutiga joylaymiz.

Bu quti klass deb ataladi.

Konsepsiya

Klass - bu chizma

Klass - o'yinchi qanday tuzilganining tavsifi.
O'zi hech narsa qilmaydi.

Bu shablon bo'lib, keyinchalik unga ko'ra haqiqiy o'yinchilar yaratiladi.

Konsepsiya

Obyekt - klassning nusxasi

Obyekt - chizmadan tug'ilgan narsa.
Bitta obyekt = o'z ismi va hp si bilan bitta haqiqiy o'yinchi.

Bitta chizmadan istalgancha obyekt yaratish mumkin.

Asosiy fikr

Bitta chizma, mingta o'yinchi

┌───────────────┐ │ class Player │ ◄── chizma └───────┬───────┘ │ ┌───────┼───────┐ ▼ ▼ ▼ Steve Alex Notch hp 20 hp 20 hp 20

Har biri o'z ma'lumotlari bilan. Chizma esa bitta.

Obyekt nimadan iborat

Obyektning ikki tarkibiy qismi

1

Obyekt o'zi haqida nimani biladi

Bu atributlar - ma'lumotlar.

2

Obyekt nima qila oladi

Bu metodlar - harakatlar.

Butun OOP - shu ikki so'z haqida.

Obyekt nimadan iborat

Atributlar: obyekt ma'lumotlari

ism sog'liq koordinata inventar tezlik

Atribut - obyektga "yopishtirilgan" o'zgaruvchi.

Har bir obyektning o'z atributlari bor.

Obyekt nimadan iborat

Metodlar: obyekt harakatlari

yurish blokni buzish yeyish sakrash hujum qilish

Metod - obyektga "yopishtirilgan" funksiya.

Bitta klassning barcha obyektlari bir xil narsani qila oladi.

Birinchi klassni yaratish

Minimal klass

class Player: def __init__(self, name, hp): self.name = name self.hp = hp

Bu butun klass. Uch qator tana.

Sintaksis

Qatorma-qator tahlil

class Player: ← keyin chizma keladi def __init__(self, ...): ← sozlovchi funksiya self.name = name ← ismni "cho'ntakka" solamiz self.hp = hp ← sog'liqni solamiz

Klass nomi - bosh harf bilan. Bu kelishuv.

Konstruktor

__init__ ning vazifasi

class Player: ← keyin chizma keladi def __init__(self, ...): ← sozlovchi funksiya self.name = name ← ismni "cho'ntakka" solamiz self.hp = hp ← sog'liqni solamiz

Biz Pythonga "o'yinchi yarat" deganimizda, u:

  1. Player chizmasini oladi
  2. bo'sh zagotovka yasaydi
  3. uni __init__ orqali o'tkazadi
  4. natijada - ism va hp ga ega tayyor o'yinchi

__init__ - initialize so'zidan, "sozlamoq".

self parametri

"Mening" olmoshi

class Player: ← keyin chizma keladi def __init__(self, ...): ← sozlovchi funksiya self.name = name ← ismni "cho'ntakka" solamiz self.hp = hp ← sog'liqni solamiz

Chizmani yozayotganimizda, biz aniq bir o'yinchining
ismi nima ekanligini hali bilmaymiz.

self - bu olmosh. Klass ichida "mening, shu aniq o'yinchining" degan ma'noni anglatadi.

self parametri

Obyektga bog'lanish

class Player: ← keyin chizma keladi def __init__(self, ...): ← sozlovchi funksiya self.name = name ← ismni "cho'ntakka" solamiz self.hp = hp ← sog'liqni solamiz
Steve bilan ishlaganda → self.name = "Steve" Alex bilan ishlaganda → self.name = "Alex"

self - obyektning o'z cho'ntaklariga murojaat qilish usuli.

Birinchi o'yinchini yaratamiz

Chizmadan Steve

class Player: ← keyin chizma keladi def __init__(self, ...): ← sozlovchi funksiya self.name = name ← ismni "cho'ntakka" solamiz self.hp = hp ← sog'liqni solamiz
steve = Player("Steve", 20) print(steve.name) print(steve.hp)
Steve 20

Nuqta "ning" deb o'qiladi: "Steve ning ismi", "Steve ning hp si".

Ko'plab obyektlar

Obyektlar mustaqilligi

class Player: ← keyin chizma keladi def __init__(self, ...): ← sozlovchi funksiya self.name = name ← ismni "cho'ntakka" solamiz self.hp = hp ← sog'liqni solamiz
steve = Player("Steve", 20) alex = Player("Alex", 20) print(steve.name, alex.name)
Steve Alex

Bitta chizma - ikkita turli obyekt.

Ko'plab obyektlar

Xotirada ikkita alohida quti

steve ──► ┌────────────────┐ │ name = "Steve" │ │ hp = 20 │ └────────────────┘ alex ──► ┌────────────────┐ │ name = "Alex" │ │ hp = 20 │ └────────────────┘

Bu ikkita turli quti. Jismonan turli.

Ko'plab obyektlar

Xotiradagi manzillar va hajm

print(id(steve)) print(id(alex)) print(steve is alex) import sys print(sys.getsizeof(steve))
140234567890 140234571248 False 48 // bayt

id() - obyektning xotiradagi noyob manzili. is manzil bo'yicha solishtiradi.

Har bir obyektga o'nlab bayt. 1000 o'yinchi ≈ 50 KB - obyektlar arzon.

Ko'plab obyektlar

O'zgaruvchi - qutidagi yorliq

steve ──► ┌────────────────┐ hero ──► │ name = "Steve" │ │ hp = 20 │ └────────────────┘
hero = steve # ikkinchi yorliq hero.hp = 5 print(steve.hp) print(steve is hero)
5 True

b = a - nusxa emas, balki o'sha qutining ikkinchi nomi.

Ko'plab obyektlar

O'zgartirishlar bir-biriga ta'sir qilmaydi

steve.hp = 0 print(alex.hp)
20 // u tirik

Obyektlar bir-biri bilan bog'liq emas.

Birini o'zgartirish boshqalariga ta'sir qilmaydi.

Ko'plab obyektlar

Ko'plab obyektlarni yaratish

server = [Player(f"Player_{i}", 20) for i in range(1000)] print(server[0].name) print(server[999].hp)
Player_0 20

Mingta o'yinchi. Har biri o'z ma'lumotlari bilan.

Hammasi shuning uchun boshlangan edi.

Klass metodlari

Parametrsiz metod

class Player: def __init__(self, name, hp): self.name = name self.hp = hp def say(self, text): print(f"<{self.name}> {text}")

Metod - klass ichidagi funksiya. Birinchi parametri har doim self.

Klass metodlari

Metodni nuqta orqali chaqirish

steve = Player("Steve", 20) steve.say("Salom, dunyo!")
<Steve> Salom, dunyo!

Nuqta orqali chaqirish. self ni Python o'zi qo'yadi.

Ichki mexanizm

Metod chaqiruvi qanday ishlaydi

Siz quyidagini yozsangiz

steve.say("Salom, dunyo!")

Python ichki tarzda buni quyidagiga aylantiradi

Player.say(steve, "Salom, dunyo!")

steve avtomatik ravishda self o'rniga tushadi.

Klass metodlari

Parametrli metod

class Player: def __init__(self, name, hp): self.name = name self.hp = hp def take_damage(self, amount): self.hp -= amount
steve = Player("Steve", 20) steve.take_damage(5) print(steve.hp)
15

Qavs ichida faqat amount. self ni Python o'zi qo'yadi.

Klass metodlari

Qiymat qaytaradigan metod

class Player: def __init__(self, name, hp): self.name = name self.hp = hp def take_damage(self, amount): self.hp -= amount def is_alive(self): return self.hp > 0
print(steve.is_alive()) steve.take_damage(100) print(steve.is_alive())
True False

Metod qiymat qaytarishi mumkin - oddiy funksiya kabi.

Klass metodlari

Metoddan metodni chaqirish

class Player: def __init__(self, name, hp): self.name = name self.hp = hp def say(self, text): print(f"<{self.name}> {text}") def eat(self, food_hp): self.hp += food_hp if self.hp > 20: self.hp = 20 self.say(f"ovqat yedi, hp: {self.hp}")

Klass ichida metodlar self orqali erkin muloqot qiladi.

Sehrli metod

__str__: print() ni boshqaramiz

class Player: def __init__(self, name, hp): self.name = name self.hp = hp def __str__(self): return f"<{self.name}> hp: {self.hp}"
steve = Player("Steve", 20) print(steve)
<Steve> hp: 20

__str__ bo'lmaganda siz <__main__.Player object at 0x7f...> ni ko'rgan bo'lardingiz - xotiradagi manzil.

Ikki tagchiziq - Python o'zi chaqiradigan "xizmatchi" metodlar uchun kelishuv.

Standart kutubxonalarda OOP

Python kodida OOP

df.head() df.groupby("city") "hello".upper() [1, 2, 3].append(4)

Har bir nuqta - bu obyektdagi metodni chaqirish.

OOP ni siz birinchi leksiyadan beri ishlatasiz, shunchaki uni shunday atamagansiz.

Misol

Satr obyekt sifatida

"hello".upper()

Satr - bu str klassining obyekti.
Uning upper metodi bor.

steve.say(...) bilan bir xil narsa. Shunchaki str klassini Python ishlab chiquvchilari yozishgan.

Misol

DataFrame klass obyekti sifatida

df = pd.read_csv("data.csv") df.head() df.shape

df - DataFrame klassining obyekti.

Metodlar: head, groupby, describe. Atributlar: shape, columns.

Bizning Player kabi aynan shunday tuzilgan - faqat metodlari yuzlab.

Misol

sklearn modellari klass sifatida

model = LinearRegression() model.fit(X, y) model.predict(X_test)

LinearRegression - klass. model - obyekt. fit/predict - metodlar.

OOP ni tushunganingizda, siz katta kutubxonalar qanday tuzilganini tushunasiz.

Amaliyot #1

1-vazifa: kengaytirilgan Player klassi

  • atributlar: name, hp (standart 20), inventory (bo'sh ro'yxat)
  • pickup(item) metodi - inventarga predmet qo'shish
  • has(item) metodi - predmet bor-yo'qligi
  • __str__ metodi - <Steve> hp: 20, items: 3
10 daqiqa

Amaliyot #1

2-vazifa: BankAccount

Xuddi shunday, lekin hayotdan:

  • atributlar: owner, balance (standart 0)
  • deposit(amount), withdraw(amount) metodlari
  • agar pul yetmasa - "Mablag' yetarli emas" deb chiqaramiz

O'yin emas - lekin xuddi shunday tuzilgan.

Tahlil

1-vazifa yechimi

class Player: def __init__(self, name, hp=20): self.name = name self.hp = hp self.inventory = [] # ← muhim: __init__ ichida def pickup(self, item): self.inventory.append(item) def has(self, item): return item in self.inventory def __str__(self): return f"<{self.name}> hp: {self.hp}, items: {len(self.inventory)}"

Tanaffus

Kofe-breyk

5–10 daq

Keyin: tun keladi, moblar paydo bo'ladi - va biz nima uchun
yuzta o'rniga bitta metod yozishimizni tushunamiz.

Takrorlanish muammosi

Yangi vazifa: moblar

Qorong'ulikdan moblar chiqadi:

Zombie

sekin yuradi va yaqin masofadan uradi

Skeleton

uzoqdan kamondan otadi

Creeper

jimgina yaqinlashadi va portlaydi

Hammasida umumiy: ism, hp, koordinata, zarar olishi mumkin.
Farqi faqat ular qanday hujum qilishida.

To'g'ridan-to'g'ri yechim

Nusxalash orqali yondashuv

class Zombie: def __init__(self, name, hp): self.name = name; self.hp = hp def take_damage(self, amount): self.hp -= amount def is_alive(self): return self.hp > 0 def attack(self, target): ... class Skeleton: def __init__(self, name, hp): self.name = name; self.hp = hp def take_damage(self, amount): self.hp -= amount def is_alive(self): return self.hp > 0 def attack(self, target): ...

Va Creeper uchun ham xuddi shunday. Yetti qator uch marta nusxalandi.

Nima uchun bunday qilib bo'lmaydi

Takrorlanish muammolari

  • Bir xil kod bir necha joyda
  • Enderman, Spider, Witch paydo bo'ladi - yana nusxalash kerak
  • take_damage da bag topdingiz - Zombie da tuzatdingiz, Skeleton da unutdingiz

Bunday qilmaymiz.

Vorislik

Vorislik g'oyasi

Umumiy narsa - bitta ota-klassga.
Noyob narsa - vorislarga.

Vorislar umumiy narsani avtomatik oladi.

Vorislik

Ota-klass

class Mob: def __init__(self, name, hp): self.name = name self.hp = hp def take_damage(self, amount): self.hp -= amount def is_alive(self): return self.hp > 0

Umumiy qism bitta joyda yig'ilgan.

Vorislik

Voris klass

class Mob: ← ota def __init__(self, name, hp): ... def take_damage(self, amount): ... def is_alive(self): ...
class Zombie(Mob): ← voris def attack(self, target): print(f"{self.name} {target.name}ni tishlaydi") target.take_damage(3)

Zombie(Mob) - "Zombie Mob dan voris bo'ladi". Ichida - faqat yangi malaka.

Bepul nima tegdi

Vorisdan foydalanish

class Mob: ← ota def __init__(self, name, hp): ... def take_damage(self, amount): ... def is_alive(self): ... class Zombie(Mob): ← voris def attack(self, target): ...
z = Zombie("Zombie-1", 20) print(z.name) # Zombie-1 - otadan kelgan atribut print(z.is_alive()) # True - otadan kelgan metod z.attack(steve) # o'z malakasi

Biz faqat attack ni aniqladik, lekin qolgan hammasi ishlaydi.

__init__ ni kengaytiramiz

Konstruktorni kengaytirish

class Mob: ← ota def __init__(self, name, hp): self.name = name self.hp = hp
class Creeper(Mob): def __init__(self, name, hp, fuse): super().__init__(name, hp) # otani chaqirish self.fuse = fuse # o'zinikini qo'shish

super().__init__(name, hp) - "ota qiladigan hamma narsani bajar, keyin men o'zimnikini qo'shaman".

Diqqat

Keng tarqalgan xato: super() siz

class Mob: ← ota, bu yerda name va hp yaratiladi def __init__(self, name, hp): self.name = name self.hp = hp
class Creeper(Mob): def __init__(self, name, hp, fuse): self.fuse = fuse # otani chaqirishni unutdik c = Creeper("Creeper-1", 20, 3) print(c.name) # AttributeError: 'Creeper' object has no attribute 'name'

__init__ ni qayta aniqladingiz - birinchi qator super().__init__(...).

So'zlar

Terminologiya

Mob

Ota-klass

parent, bazaviy, superklass

Zombie, Skeleton, Creeper

Voris klasslar

child, vorislar, voris klasslar

Zombie(Mob) yozuvi quyidagicha o'qiladi: "Zombie - bu Mob plyus yana bir narsa".

Qayta aniqlash va polimorfizm

Metodni qayta aniqlash

class Zombie(Mob): def attack(self, target): print(f"{self.name} {target.name}ni tishlaydi") target.take_damage(3) class Skeleton(Mob): def attack(self, target): print(f"{self.name} {target.name}ga otadi") target.take_damage(2) class Creeper(Mob): def attack(self, target): print(f"{self.name}: SSSSS... BUM!") target.take_damage(15)

Bir xil metod nomi - turli amalga oshirish.

Qaysi versiyani chaqirish kerak?

Chaqiruvda amalga oshirishni tanlash

z = Zombie("Zombie-1", 20) s = Skeleton("Skeleton-1", 20) c = Creeper("Creeper-1", 20, 3) z.attack(steve) s.attack(steve) c.attack(steve)
Zombie-1 Steveni tishlaydi Skeleton-1 Stevega otadi Creeper-1: SSSSS... BUM!

Python obyekt turiga qaraydi va kerakli attack versiyasini chaqiradi.

Bitta sikldagi sehr

Polimorfizm amalda

night = [ Zombie("Z-1", 20), Skeleton("S-1", 20), Creeper("C-1", 20, 3), Zombie("Z-2", 20), ] for mob in night: if mob.is_alive(): mob.attack(steve)

Siklga ichkarida kim borligi muhim emas. U shunchaki .attack() ni chaqiradi.

Mana shu polimorfizm deb ataladi. G'oyasi oddiy: bitta interfeys, turli xatti-harakat.

Real loyihalarda OOP

sklearn da polimorfizm

from sklearn.linear_model import LinearRegression from sklearn.tree import DecisionTreeRegressor models = [LinearRegression(), DecisionTreeRegressor()] for m in models: m.fit(X, y) m.predict(X_test)

Turli modellar - bitta fit/predict interfeysi.

Moblar bilan bo'lgan o'sha sikl.

Bu ham vorislik

Istisnolar ierarxiyasi

Exception ├── ValueError ├── KeyError ├── TypeError └── ...

ValueError - Exception ning bir turi.

Siz except Exception deb yozsangiz - hammasi ushlanadi, chunki vorislik bor.

Tez-tez uchraydigan xatolar

1-xato: tushib qolgan self

class Player: def __init__(self, name): name = name # ⚠ lokal o'zgaruvchi yaratdik steve = Player("Steve") print(steve.name) # AttributeError

Atribut faqat self.nom = ... orqali yaratiladi

Tez-tez uchraydigan xatolar

2-xato: tushib qolgan super().__init__()

class Creeper(Mob): def __init__(self, name, hp, fuse): self.fuse = fuse # ⚠ ota chaqirilmadi c = Creeper("Creeper-1", 20, 3) print(c.name) # AttributeError

__init__ ni qayta aniqladingiz - birinchi qator super().__init__(...).

Tez-tez uchraydigan xatolar

3-xato: o'zgaruvchan klass atributi

class Player: inventory = [] # ⚠ barcha o'yinchilar uchun bitta def pickup(self, item): self.inventory.append(item) steve.pickup("qilich") print(alex.inventory) # ['qilich'] - Alex da ham!

Ro'yxatlar va lug'atlar - faqat __init__ ichida, klass darajasida emas.

Amaliyot #2

Vazifa: Animal ierarxiyasi

Maynkraftsiz - oddiy misolda usulni mustahkamlaymiz.

  • Animal(name) va sound() = "..." metodi bilan
  • Dog(Animal) sound() = "Vov" ni qayta aniqlaydi
  • Cat(Animal) sound() = "Miyov" ni qayta aniqlaydi
  • Animal dagi describe() metodi: "{name} {sound()} deydi"
  • Hayvonlar ro'yxatini yarating va u bo'ylab yuring
10 daqiqa

Tahlil

Kutilayotgan natija

zoo = [Dog("Reks"), Cat("Murka")] for a in zoo: print(a.describe())
Reks Vov deydi Murka Miyov deydi

Zombie/Skeleton/Creeper bilan bo'lgan o'sha usul. O'sha sikl. Shunchaki boshqa ismlar.

Yakunlar

Biz nimani o'rgandik

  • klass - chizma
  • obyekt - chizmadan tug'ilgan narsa
  • atributlar va metodlar - obyekt nimani biladi va nima qila oladi
  • self - klass ichidagi "mening"
  • __str__ - obyekt qanday chop etilishini boshqaramiz
  • vorislik - umumiy narsa otaga, noyob narsa vorislarga
  • super() - otani chaqirish
  • polimorfizm - bitta interfeys, turli xatti-harakat

Yakunlar

Real ishda qo'llanilishi

Siz df.groupby(...) yoki model.fit(...) ni ko'rganingizda, endi buning ichida qanday tuzilganini bilasiz.

  • Manba kodga kirish mumkin
  • Kutubxonalar ustiga o'z klasslaringizni yozish mumkin
  • Python kodning katta qismi - bu klasslar

Yakun

Savollar?

Telegram: @gokalqurt

RU UZ EN
Python · Leksiya 4
1 / 62