12. Obyektga yo‘naltirilgan dasturlash

Obyektga yo‘naltirilgan dasturlash — dasturdagi ma’lumot va ular bilan ishlaydigan funksiyalarni obyektlar atrofida tashkil qilish usulidir.

Python'da obyektga yo‘naltirilgan dasturlashning asosiy tushunchalari:

class
obyekt
atribut
metod
__init__
self
meros olish
polimorfizm
inkapsulyatsiya

Class nima?

class obyektlar uchun andoza hisoblanadi.

Masalan, foydalanuvchi uchun class yaratamiz:

class Foydalanuvchi:

    pass

Bu hali hech qanday xususiyatga ega emas.

Undan obyekt yaratish mumkin:

foydalanuvchi = Foydalanuvchi()

print(
    foydalanuvchi
)

Obyekt nima?

Class — andoza.

Obyekt — shu andoza asosida yaratilgan aniq nusxa.

class Foydalanuvchi:

    pass


birinchi_foydalanuvchi = (
    Foydalanuvchi()
)

ikkinchi_foydalanuvchi = (
    Foydalanuvchi()
)

Bu yerda ikkita alohida obyekt mavjud:

Foydalanuvchi
    ↓
birinchi_foydalanuvchi

Foydalanuvchi
    ↓
ikkinchi_foydalanuvchi

Atribut

Obyektning ma’lumotlari atribut deyiladi.

class Foydalanuvchi:

    pass


foydalanuvchi = Foydalanuvchi()

foydalanuvchi.ism = (
    "Softromeda"
)

foydalanuvchi.yosh = 25

print(
    foydalanuvchi.ism
)

print(
    foydalanuvchi.yosh
)

Natija:

Softromeda
25

__init__

Obyekt yaratilganida avtomatik bajariladigan maxsus metod __init__ deyiladi.

class Foydalanuvchi:

    def __init__(
        self,
        ism,
        yosh
    ):

        self.ism = ism
        self.yosh = yosh

Obyekt yaratish:

foydalanuvchi = Foydalanuvchi(
    "Softromeda",
    25
)

print(
    foydalanuvchi.ism
)

print(
    foydalanuvchi.yosh
)

self

self joriy obyektni bildiradi.

class Foydalanuvchi:

    def __init__(
        self,
        ism,
        yosh
    ):

        self.ism = ism
        self.yosh = yosh

Bu yerda:

self.ism
    ↓
joriy obyektning ismi

self.yosh
    ↓
joriy obyektning yoshi

Masalan:

birinchi_foydalanuvchi = Foydalanuvchi(
    "Ali",
    25
)

ikkinchi_foydalanuvchi = Foydalanuvchi(
    "Vali",
    30
)

Har bir obyekt o‘zining qiymatlarini saqlaydi.


Metod

Class ichidagi funksiya metod deyiladi.

class Foydalanuvchi:

    def __init__(
        self,
        ism
    ):

        self.ism = ism

    def salomlash(
        self
    ):

        print(
            f"Salom, {self.ism}!"
        )

Foydalanish:

foydalanuvchi = Foydalanuvchi(
    "Softromeda"
)

foydalanuvchi.salomlash()

Natija:

Salom, Softromeda!

Metodga parametr berish

class Hisob:

    def __init__(
        self,
        egasi
    ):

        self.egasi = egasi
        self.balans = 0

    def pul_qoshish(
        self,
        miqdor
    ):

        self.balans += miqdor

    def balansni_korsatish(
        self
    ):

        print(
            f"Balans: {self.balans}"
        )

Foydalanish:

hisob = Hisob(
    "Softromeda"
)

hisob.pul_qoshish(
    100000
)

hisob.balansni_korsatish()

Natija:

Balans: 100000

Bir nechta obyekt

Bitta class asosida istalgancha obyekt yaratish mumkin.

class Foydalanuvchi:

    def __init__(
        self,
        ism,
        yosh
    ):

        self.ism = ism
        self.yosh = yosh

    def malumot_korsatish(
        self
    ):

        print(
            f"Ism: {self.ism}"
        )

        print(
            f"Yosh: {self.yosh}"
        )


birinchi_foydalanuvchi = Foydalanuvchi(
    "Ali",
    25
)

ikkinchi_foydalanuvchi = Foydalanuvchi(
    "Vali",
    30
)

birinchi_foydalanuvchi.malumot_korsatish()

ikkinchi_foydalanuvchi.malumot_korsatish()

Class atributi

Ba’zi ma’lumotlar barcha obyektlar uchun umumiy bo‘lishi mumkin.

Bunday ma’lumotni class atributi sifatida yaratish mumkin.

class Foydalanuvchi:

    platforma_nomi = "Softromeda"

    def __init__(
        self,
        ism
    ):

        self.ism = ism

Foydalanish:

birinchi_foydalanuvchi = Foydalanuvchi(
    "Ali"
)

ikkinchi_foydalanuvchi = Foydalanuvchi(
    "Vali"
)

print(
    birinchi_foydalanuvchi.platforma_nomi
)

print(
    ikkinchi_foydalanuvchi.platforma_nomi
)

Ikkalasida ham:

Softromeda

chiqadi.


Instance atribut va class atribut

Quyidagi:

self.ism

obyektga tegishli.

Quyidagi:

platforma_nomi

esa classga tegishli.

class Foydalanuvchi:

    platforma_nomi = "Softromeda"

    def __init__(
        self,
        ism
    ):

        self.ism = ism

Class metod

@classmethod classning o‘zi bilan ishlaydigan metod yaratadi.

class Foydalanuvchi:

    platforma_nomi = "Softromeda"

    def __init__(
        self,
        ism
    ):

        self.ism = ism

    @classmethod
    def platformani_korsatish(
        cls
    ):

        print(
            cls.platforma_nomi
        )

Foydalanish:

Foydalanuvchi.platformani_korsatish()

Natija:

Softromeda

Bu yerda cls classning o‘zini bildiradi.


Statik metod

@staticmethod obyekt yoki classning avtomatik parametrini talab qilmaydi.

class Hisoblagich:

    @staticmethod
    def qoshish(
        birinchi_son,
        ikkinchi_son
    ):

        return (
            birinchi_son
            + ikkinchi_son
        )

Foydalanish:

natija = Hisoblagich.qoshish(
    10,
    20
)

print(
    natija
)

Natija:

30

Oddiy metod, class metod va statik metod

Ularning farqi:

oddiy metod
    → self

class metod
    → cls

statik metod
    → self yoki cls kerak emas

Meros olish

Bir class boshqa classning xususiyat va metodlarini meros qilib olishi mumkin.

class Inson:

    def __init__(
        self,
        ism
    ):

        self.ism = ism

    def salomlash(
        self
    ):

        print(
            f"Salom, {self.ism}!"
        )


class Dasturchi(
    Inson
):

    pass

Endi:

dasturchi = Dasturchi(
    "Softromeda"
)

dasturchi.salomlash()

Natija:

Salom, Softromeda!

Dasturchi Insondan meros oldi.


Ota class va bola class

Terminlar:

ota class
parent class
base class
superclass

va:

bola class
child class
subclass

Masalan:

class Inson:

    pass


class Dasturchi(
    Inson
):

    pass

Bu yerda:

Inson
 ↓
Dasturchi

Meros bilan __init__

class Inson:

    def __init__(
        self,
        ism
    ):

        self.ism = ism


class Dasturchi(
    Inson
):

    def __init__(
        self,
        ism,
        dasturlash_tili
    ):

        super().__init__(
            ism
        )

        self.dasturlash_tili = (
            dasturlash_tili
        )

Foydalanish:

dasturchi = Dasturchi(
    "Softromeda",
    "Python"
)

print(
    dasturchi.ism
)

print(
    dasturchi.dasturlash_tili
)

super()

super() ota classdagi metodga murojaat qilish uchun ishlatiladi.

class Inson:

    def __init__(
        self,
        ism
    ):

        self.ism = ism


class Dasturchi(
    Inson
):

    def __init__(
        self,
        ism,
        tajriba
    ):

        super().__init__(
            ism
        )

        self.tajriba = tajriba

Bu kod:

super().__init__(
    ism
)

orqali Inson.__init__()ni chaqiradi.


Metodni qayta aniqlash

Bola class ota classdagi metodni o‘zgartirishi mumkin.

class Inson:

    def salomlash(
        self
    ):

        print(
            "Salom!"
        )


class Dasturchi(
    Inson
):

    def salomlash(
        self
    ):

        print(
            "Salom, men dasturchiman!"
        )

Foydalanish:

inson = Inson()

dasturchi = Dasturchi()

inson.salomlash()

dasturchi.salomlash()

Natija:

Salom!
Salom, men dasturchiman!

Bu overriding deyiladi.


Polimorfizm

Polimorfizm — bir xil metod nomi turli obyektlarda turlicha ishlashi.

class Dasturchi:

    def kasbni_aytish(
        self
    ):

        print(
            "Men dasturchiman."
        )


class Muhandis:

    def kasbni_aytish(
        self
    ):

        print(
            "Men muhandisman."
        )


kasblar = [
    Dasturchi(),
    Muhandis()
]

for kasb in kasblar:

    kasb.kasbni_aytish()

Natija:

Men dasturchiman.
Men muhandisman.

Bir xil metod:

kasb.kasbni_aytish()

turli obyektlarda turlicha ishladi.


Inkapsulyatsiya

Inkapsulyatsiya obyektning ichki ma’lumotlarini nazorat qilish va tashqi kod bilan qanday ishlashini belgilash g‘oyasidir.

Python'da nom oldiga _ qo‘yish odatda ichki foydalanish uchun ekanini bildiradi.

class Hisob:

    def __init__(
        self,
        balans
    ):

        self._balans = balans

    def balansni_olish(
        self
    ):

        return self._balans

Foydalanish:

hisob = Hisob(
    100000
)

print(
    hisob.balansni_olish()
)

Ikki pastki chiziq

__ bilan boshlanadigan atributlar name mangling mexanizmidan foydalanadi.

class Hisob:

    def __init__(
        self,
        balans
    ):

        self.__balans = balans

Tashqaridan:

hisob = Hisob(
    100000
)

print(
    hisob.__balans
)

to‘g‘ridan-to‘g‘ri ishlamaydi.

Odatda unga metod orqali murojaat qilinadi:

class Hisob:

    def __init__(
        self,
        balans
    ):

        self.__balans = balans

    def balansni_olish(
        self
    ):

        return self.__balans

Property

@property atributga metod kabi boshqariladigan kirish yaratishga imkon beradi.

class Foydalanuvchi:

    def __init__(
        self,
        ism
    ):

        self._ism = ism

    @property
    def ism(
        self
    ):

        return self._ism

Foydalanish:

foydalanuvchi = Foydalanuvchi(
    "Softromeda"
)

print(
    foydalanuvchi.ism
)

Bu yerda:

foydalanuvchi.ism

metod chaqirishga o‘xshab:

foydalanuvchi.ism()

yozilmaydi.


Property orqali qiymatni tekshirish

class Foydalanuvchi:

    def __init__(
        self,
        yosh
    ):

        self.yosh = yosh

    @property
    def yosh(
        self
    ):

        return self._yosh

    @yosh.setter
    def yosh(
        self,
        qiymat
    ):

        if qiymat < 0:

            raise ValueError(
                "Yosh manfiy bo‘lishi mumkin emas."
            )

        self._yosh = qiymat

Endi:

foydalanuvchi = Foydalanuvchi(
    25
)

print(
    foydalanuvchi.yosh
)

Noto‘g‘ri qiymat:

foydalanuvchi.yosh = -5

xatolik chiqaradi.


Maxsus metodlar

Python'da __ bilan boshlanadigan maxsus metodlar mavjud.

Masalan:

__init__
__str__
__repr__
__len__
__eq__

Ular Python tomonidan maxsus vaziyatlarda chaqiriladi.


__str__

Obyektni foydalanuvchiga tushunarli ko‘rinishda chiqarish uchun __str__ ishlatiladi.

class Foydalanuvchi:

    def __init__(
        self,
        ism,
        yosh
    ):

        self.ism = ism
        self.yosh = yosh

    def __str__(
        self
    ):

        return (
            f"{self.ism}, "
            f"{self.yosh} yosh"
        )

Foydalanish:

foydalanuvchi = Foydalanuvchi(
    "Softromeda",
    25
)

print(
    foydalanuvchi
)

Natija:

Softromeda, 25 yosh

__len__

Obyekt uchun len() qanday ishlashini belgilash mumkin.

class Jamoa:

    def __init__(
        self,
        azolar
    ):

        self.azolar = azolar

    def __len__(
        self
    ):

        return len(
            self.azolar
        )

Foydalanish:

jamoa = Jamoa(
    [
        "Ali",
        "Vali",
        "Sami"
    ]
)

print(
    len(jamoa)
)

Natija:

3

__eq__

Ikki obyektni == bilan solishtirishni belgilash mumkin.

class Foydalanuvchi:

    def __init__(
        self,
        ism
    ):

        self.ism = ism

    def __eq__(
        self,
        boshqa
    ):

        return (
            self.ism
            == boshqa.ism
        )

Foydalanish:

birinchi_foydalanuvchi = Foydalanuvchi(
    "Ali"
)

ikkinchi_foydalanuvchi = Foydalanuvchi(
    "Ali"
)

print(
    birinchi_foydalanuvchi
    == ikkinchi_foydalanuvchi
)

Natija:

True

Kompozitsiya

Obyekt boshqa obyektni o‘z ichida saqlashi mumkin.

Masalan:

class Dvigatel:

    def ishga_tushirish(
        self
    ):

        print(
            "Dvigatel ishga tushdi."
        )


class Mashina:

    def __init__(
        self
    ):

        self.dvigatel = Dvigatel()

    def ishga_tushirish(
        self
    ):

        self.dvigatel.ishga_tushirish()

Foydalanish:

mashina = Mashina()

mashina.ishga_tushirish()

Bu yerda Mashina ichida Dvigatel obyekti mavjud.


Bir nechta meros olish

Python bir nechta classdan meros olishga imkon beradi.

class Yuruvchi:

    def yurish(
        self
    ):

        print(
            "Yurish amalga oshirildi."
        )


class Suzuvchi:

    def suzish(
        self
    ):

        print(
            "Suzish amalga oshirildi."
        )


class Sportchi(
    Yuruvchi,
    Suzuvchi
):

    pass

Foydalanish:

sportchi = Sportchi()

sportchi.yurish()

sportchi.suzish()

MRO

Bir nechta meros olishda Python metodni qaysi classdan izlash tartibini MRO orqali belgilaydi.

print(
    Sportchi.mro()
)

MRO:

Method Resolution Order

ya’ni metodlarni qidirish tartibi.


Abstract class

Ba’zan ota class faqat umumiy interfeysni belgilashi kerak.

Buning uchun abc modulidan foydalanish mumkin.

from abc import ABC, abstractmethod


class Transport(
    ABC
):

    @abstractmethod
    def harakatlanish(
        self
    ):

        pass

Endi bola class bu metodni amalga oshirishi kerak:

class Mashina(
    Transport
):

    def harakatlanish(
        self
    ):

        print(
            "Mashina yo‘lda harakatlanmoqda."
        )

Obyektlar bilan ishlash

Bir nechta foydalanuvchini listda saqlash mumkin.

class Foydalanuvchi:

    def __init__(
        self,
        ism,
        yosh
    ):

        self.ism = ism
        self.yosh = yosh

    def malumot_korsatish(
        self
    ):

        print(
            f"{self.ism} - "
            f"{self.yosh} yosh"
        )


foydalanuvchilar = [
    Foydalanuvchi(
        "Ali",
        25
    ),
    Foydalanuvchi(
        "Vali",
        30
    ),
    Foydalanuvchi(
        "Sami",
        28
    )
]

for foydalanuvchi in foydalanuvchilar:

    foydalanuvchi.malumot_korsatish()

Obyektlardan foydalanishning foydasi

Oddiy dasturda ma’lumotlar:

ism = "Ali"
yosh = 25
kasb = "Dasturchi"

ko‘rinishida bo‘lishi mumkin.

Class yordamida esa:

class Foydalanuvchi:

    def __init__(
        self,
        ism,
        yosh,
        kasb
    ):

        self.ism = ism
        self.yosh = yosh
        self.kasb = kasb

    def malumot_korsatish(
        self
    ):

        print(
            f"Ism: {self.ism}"
        )

        print(
            f"Yosh: {self.yosh}"
        )

        print(
            f"Kasb: {self.kasb}"
        )

Ma’lumot va ular bilan ishlaydigan xatti-harakatlar bir joyda jamlanadi.


Amaliy mashqlar

Mashq 1

Foydalanuvchi classini yarating.

U quyidagilarni saqlasin:

ism
yosh
email

Mashq 2

Foydalanuvchi classiga:

malumot_korsatish()

metodini qo‘shing.

Mashq 3

Hisob classini yarating.

Unda:

pul_qoshish()
pul_yechish()
balansni_korsatish()

metodlari bo‘lsin.

Mashq 4

Transport classidan:

Mashina
Velosiped

classlarini meros qildiring.

Mashq 5

Har ikkala classda:

harakatlanish()

metodini alohida amalga oshiring.

Mashq 6

@property yordamida yoshni tekshiring.

Mashq 7

__str__ metodini amalga oshiring.

Mashq 8

Ikki obyektni == orqali solishtirish uchun __eq__ metodini yozing.


Mini loyiha — Softromeda hisob tizimi

class Hisob:

    def __init__(
        self,
        egasi
    ):

        self.egasi = egasi
        self._balans = 0

    @property
    def balans(
        self
    ):

        return self._balans

    def pul_qoshish(
        self,
        miqdor
    ):

        if miqdor <= 0:

            raise ValueError(
                "Qo‘shiladigan pul 0 dan katta bo‘lishi kerak."
            )

        self._balans += miqdor

    def pul_yechish(
        self,
        miqdor
    ):

        if miqdor <= 0:

            raise ValueError(
                "Yechiladigan pul 0 dan katta bo‘lishi kerak."
            )

        if miqdor > self._balans:

            raise ValueError(
                "Balansda yetarli mablag‘ mavjud emas."
            )

        self._balans -= miqdor

    def malumot_korsatish(
        self
    ):

        print(
            f"Hisob egasi: {self.egasi}"
        )

        print(
            f"Balans: {self._balans}"
        )

    def __str__(
        self
    ):

        return (
            f"{self.egasi}: "
            f"{self._balans} so‘m"
        )


hisob = Hisob(
    "Softromeda"
)

try:

    hisob.pul_qoshish(
        500000
    )

    hisob.pul_yechish(
        150000
    )

    hisob.malumot_korsatish()

    print(
        hisob
    )

except ValueError as xatolik:

    print(
        f"Xatolik: {xatolik}"
    )

Natija:

Hisob egasi: Softromeda
Balans: 350000
Softromeda: 350000 so‘m

Bob xulosasi

Bu bobda Python'da obyektga yo‘naltirilgan dasturlashni o‘rgandik.

Asosiy tushunchalar:

class
obyekt
atribut
metod
self
__init__

Classlar orasidagi munosabatlar:

meros olish
super()
overriding
polimorfizm
kompozitsiya

Qo‘shimcha imkoniyatlar:

classmethod
staticmethod
property
abstractmethod

Maxsus metodlar:

__init__
__str__
__repr__
__len__
__eq__

Obyektga yo‘naltirilgan dasturlash katta dasturlarni ma’lumotlar va ularning xatti-harakatlari asosida tartibli tashkil qilishga yordam beradi.

Keyingi bobda Python modullari, paketlar, import tizimi va loyihalarni bir nechta faylga ajratishni o‘rganamiz.