Barcha qo'llanmalar

Python super() va init: multiple inheritance bo'yicha qo'llanma

Subclass'ingiz nega buzilayotganini taxmin qilishni bas qiling. super() va init qanday birga ishlashini single inheritance'dan multiple inheritance'gacha, misollar bilan ko'ring.

Muallif: Kimberly Fessel

Funksiya bilan method sinfga kirib kelibdi. Bu yomon informatika latifasining boshlanishiga o'xshaydi, lekin aslida bu hamkorlik, u yer-bu yerdagi bir nechta argument va inheritance ierarxiyasiga qurilgan go'zal munosabatning boshlanishidir.

Python'da inheritance sizga base class'lardagi attribute va method'larni qayta ishlatish hamda kengaytirish imkoniyatini beradi. O'rta darajadagi Pythonista'lar uchun mo'ljallangan ushbu maqolada sinf instance'larini initialization qilish uchun __init__() method'ini, shuningdek, boshqa sinflardan meros qilib olingan method'larga murojaat qilish uchun super() funksiyasini tushuntiramiz. Ikkalasini qanday birga ishlatishni, multiple inheritance va MRO bilan ishlashni hamda yo'l-yo'lakay keng tarqalgan "tuzoq"lardan qochishni o'rganasiz.

Python'da __init__: obyekt initialization'i

Python'da sinflar yaratayotganda ko'pincha o'sha sinf instance'larini ism, yosh yoki boshqa tafsilotlar kabi muayyan property'lar bilan initialization qilishni xohlaysiz. __init__() deb ataladigan maxsus method aynan shunga yordam beradi. Instance yaratganingizda Python sinfning __init__()'ini avtomatik ravishda chaqiradi. Bu obyektning boshlang'ich holati uchun attribute'larni o'rnatish imkonini beradi va ularga Python kodingizning istalgan joyida murojaat qilishingiz mumkin.

Yangi yaratilgan instance'ingizga odatda __init__()'ning birinchi argumenti bo'lgan self orqali murojaat qilasiz. So'ng instance attribute'larini quyidagicha ko'rsatishingiz mumkin: self.attribute. Shuningdek, parameter'larga None default qiymatini berib, ularni instance yaratishda ixtiyoriy qilishingiz ham mumkin.

Quyida ikkita attribute'ga ega Employee sinfiga misol keltirilgan: name va employee_id:

class Employee:
    def __init__(self, name, employee_id):
        self.name = name
        self.employee_id = employee_id

Endi ism va xodim ID'sini berib, bu sinfning instance'ini yaratishingiz mumkin. Yaratilgandan keyin ism yoki xodim ID'sini instance.attribute ko'rinishida topasiz:

print(employee.name)
print(employee.employee_id)

# Expected result:
# Louisa Templeton
# 1234

Python super(): single inheritance misoli

Python sinflari ko'p vaziyatlarda foydali ekanini ko'rasiz va ma'lum bo'lishicha, ularning foydasini yakka obyektlarning oddiy tavsifidan ham kengroq qilish mumkin. Ixtisoslashgan subclass'lar (child class'lar) superclass'lardan (parent class'lar yoki boshqalardan) meros olishi mumkin. Superclass uning barcha subclass'lari qabul qilishi mumkin bo'lgan umumiy attribute va method'larni tavsiflaydi, subclass'lar esa muayyan qiymatlar va amallarni qo'shishi yoki override qilishi mumkin. Sinflar encapsulation'ni ham qo'llab-quvvatlaydi: ular ma'lumotlar va method'larni birga jamlab, sinf tashqarisidan kirishni nazorat qiladi.

Keling, bu inheritance Python'da qanday ishlashini Employee sinfimizga asoslangan RemoteWorker subclass'i misolida tushuntiramiz:

class Employee:
    def __init__(self, name, employee_id):
        self.name = name
        self.employee_id = employee_id

class RemoteWorker(Employee):
    pass

worker = RemoteWorker("Salvadore Russo", 5678)

print(worker.name)
print(worker.employee_id)

# Expected result:
# Salvadore Russo
# 5678

RemoteWorker child class'i o'zining __init__()'ini aniqlamagani uchun u base class'i Employee'dan meros qilib olingan initializer'dan foydalanadi. Ammo RemoteWorker uchun vaqt mintaqasi kabi qo'shimcha attribute'lar bo'lsa-chi? RemoteWorker'ning o'z __init__()'i bo'lganda nima sodir bo'lishini ko'ring:

class Employee:
    def __init__(self, name, employee_id):
        self.name = name
        self.employee_id = employee_id

class RemoteWorker(Employee):
    def __init__(self, timezone):
        self.timezone = timezone

worker = RemoteWorker("Salvadore Russo", 5678, "US Eastern")

# Expected result:
# TypeError: RemoteWorker.__init__() takes 2 positional arguments but 4 were given

RemoteWorker sinfimiz bevosita superclass'i sifatida Employee'dan meros oldi, lekin u o'zining __init__()'ini aniqlagani sababli, RemoteWorker instance'ini yaratganingizda Python aynan shu initializer'ni chaqiradi. U Employee.__init__()'ni avtomatik ravishda chaqirmaydi.

RemoteWorker'ga yangi attribute qo'shgan holda Employee'ning initialization'idan qayta foydalanish uchun super()'ni ishlating. super() — built-in Python funksiyasi bo'lib, method chaqiruvlarini inheritance ierarxiyasidagi boshqa sinfga delegate qilish imkonini beradi. Yangilangan kod quyida:

class Employee:
    def __init__(self, name, employee_id):
        self.name = name
        self.employee_id = employee_id

class RemoteWorker(Employee):
    def __init__(self, name, employee_id, timezone):  	# All attributes
        self.timezone = timezone
        super().__init__(name, employee_id)  		# Here’s super()  

worker = RemoteWorker("Salvadore Russo", 5678, "US Eastern")

print(worker.name)
print(worker.timezone)

# Expected result:
# Salvadore Russo
# US Eastern

Bu yerdagi asosiy kod satri — super().__init__(name, employee_id). Ushbu oddiy misolda Employee — RemoteWorker child class'ining parent class'i, shuning uchun super() Python'ning method resolution order'i (MRO) bo'yicha keyingi bo'lib Employee.__init__()'ni topadi va unga name hamda employee_id'ni uzatadi. E'tibor bering, self'ni uzatishingiz shart emas — Python uni avtomatik ravishda beradi.

Python super() funksiyasisiz parent class funksiyasini hard-code qilishingiz kerak bo'lardi, parent class'ni aniq chaqirish esa MRO'dagi boshqa implementation'larni tasodifan o'tkazib yuborishi va sinfning moslashuvchanligini cheklashi mumkin. Shuning uchun keling, multiple inheritance'ni, jumladan har doim muhim bo'lgan MRO'ni batafsilroq ko'rib chiqamiz.

Multiple inheritance va MRO

Siz hozirgina oddiy inheritance misolini ko'rdingiz: RemoteWorker sinfi Employee sinfidan meros oldi. Ammo sinf bittadan ko'p base class'dan meros olsa nima bo'ladi? Bu multiple inheritance'ga olib keladi va u Python'da keng tarqalgan.

Aytaylik, sizda Employee'dan meros oladigan TeamLead nomli yana bir sinf va ham RemoteWorker'dan, ham TeamLead'dan hosil qilingan to'rtinchi sinf — EngineeringManager bor. Bu to'rt sinfni olmos shaklida tasavvur qilishingiz mumkin:

Python'da multiple inheritance

Bunday inheritance noaniqlikka sabab bo'lishi mumkin, chunki ikkala yo'l ham Employee'ga qaytib boradi. Bir nechta sinf bir xil method'ni aniqlaganda qaysi biri ustunlikka ega bo'lishi kerak? Python'ga meros qilib olingan ma'lumotni qayerdan qidirishni aniqlash uchun qoidalar kerak.

MRO nima?

MRO, ya'ni method resolution order, Python sinfning inheritance ierarxiyasida method'larni qidirish uchun foydalanadigan aniq tartiblangan ketma-ketlikni beradi. Har bir Python sinfining MRO'si bor. Ko'pincha single inheritance'ga ega oddiy sinflarda MRO subclass'dan uning superclass'lari tomon oddiy chiziqli ierarxiya bo'yicha boradi. Biroq sinflar ko'plab boshqa sinflardan meros olganda MRO hal qiluvchi ahamiyatga ega bo'ladi — bir xil nomli method'ni bittadan ko'p sinf aniqlaganda Python qaysi method ustun ekanini shu orqali biladi.

Istalgan Python sinfining MRO'sini mana bunday tekshirishingiz mumkin: EngineeringManager.mro() yoki EngineeringManager.__mro__

Yuqorida tasvirlangan EngineeringManager misoli uchun EngineeringManager → RemoteWorker → TeamLead → Employee → object (umumiy Python sinfi) kabi zanjirni ko'rishni kutamiz:

print(EngineeringManager.__mro__)

# Expected result:

# (<class '__main__.EngineeringManager'>, <class '__main__.RemoteWorker'>, <class '__main__.TeamLead'>, <class '__main__.Employee'>, <class 'object'>)

Python MRO tartibini C3 linearization deb ataladigan algoritm yordamida aniqlaydi: u sinflar ierarxiyasini va base class'larni sanab o'tgan tartibingizni hurmat qiladigan izchil tartib hosil qiladi. Child class MRO'da har doim o'zining barcha parent class'laridan oldin keladi, bir nechta sinfdan meros olish murakkabroq munosabatlarni yuzaga keltirganda esa sinflar o'rtasidagi tartibni C3 linearization belgilaydi.

Multiple inheritance'da super qanday chaqiriladi?

super()'ni chaqirish super obyektini yaratadi, u Python'ga MRO'dagi (Method Resolution Order) keyingi sinfdan boshlab method'larni qidirish imkonini beradi. U bajarish uchun shu nomdagi method'ni topmaguncha MRO bo'ylab yuqoriga qarab qidirishda davom etadi. Agar bunday method mavjud bo'lmasa, AttributeError olasiz. E'tibor bering, super()'dan foydalanish shunchaki parent class'dan ma'lumot qidirish bilan bir xil narsa emas. Python super() funksiyasi MRO bo'ylab tizimli ravishda yuqoriga harakatlanadi va bu ko'p sinfli inheritance holatida eng yaqqol ko'rinadi.

Aniq misol uchun, har bir sinfda sinf nomini chiqaradigan va super().describe()'ni chaqiradigan .describe() nomli method bor deb tasavvur qiling. Quyidagi kodda EngineeringManager instance'ida .describe()'ni ishga tushirib, butun MRO'ni ko'rishingiz mumkin:

class Employee:
    def describe(self):
        print("Employee")

class RemoteWorker(Employee):
    def describe(self):
        print("Remote Worker")
        super().describe()

class TeamLead(Employee):
    def describe(self):
        print("Team Lead")
        super().describe()

class EngineeringManager(RemoteWorker, TeamLead):
    def describe(self):
        print("Engineering Manager")
        super().describe()

manager = EngineeringManager()
manager.describe()

# Expected result:
# Engineering Manager
# Remote Worker
# Team Lead
# Employee

describe()'ning har bir implementation'i super.describe()'ni chaqiradi, bu esa chaqiruvga MRO'dagi keyingi implementation'ga o'tishda davom etish imkonini beradi, toki zanjir Employee.describe() bilan tugaguncha. Ajablanarlisi shundaki, RemoteWorker ichidagi super().describe() TeamLead'ga olib boradi, holbuki u undan meros olmaydi. Python shunchaki child class'dan parent class'ga sakrab o'tmaydi, balki MRO'ga amal qiladi.

Cooperative Multiple Inheritance

Oldingi misolda kod MRO'dagi har bir sinfga o'zining .describe()'ini bajarish imkonini berdi, chunki subclass'lar ham super().describe()'ni chaqirdi. Bu cooperation'ga, ya'ni hamkorlikka misol bo'ldi. Bu yerda "cooperative" har bir sinf method'ning o'ziga tegishli qismini bajaradi va so'ng MRO'dagi keyingi sinfga o'z qismini bajarish imkonini berish uchun super()'dan foydalanadi degan ma'noni bildiradi.

Cooperative multiple inheritance'da muayyan superclass'ni hard-code qilish yomon fikr bo'lishi mumkin. Mustahkamlik uchun super()'dan foydalanib, keyingi qaysi implementation kelishini MRO'ga belgilashga imkon bergan ma'qul. Biroq hamkorlik har bir ishtirokchi sinf zanjirni davom ettirishiga bog'liq. Agar biror sinf super()'ni qo'shmasa, MRO'da keyinroq turgan sinflar o'z method'larini ishga tushirish imkoniyatiga hech qachon ega bo'lmasligi mumkin.

Gap __init__() haqida ketganda, cooperative ko'p sinfli inheritance nihoyatda muhim ahamiyat kasb etadi. Hamkorlik tufayli MRO'dagi har bir sinf o'z initialization'ini bajarish imkoniyatiga ega bo'ladi. Initialization'ingizni cooperative qilayotganda, ehtimol, **kwargs'dan foydalanishni xohlaysiz — u har bir sinfga qo'shimcha keyword argument'larni qabul qilish va uzatish imkonini beradi.

Bu pattern bir nechta sinf initialization'ga hissa qo'shishi kerak bo'lgan EngineeringManager'imiz uchun mantiqli:

class Employee:
    def __init__(self, name, employee_id, **kwargs):
        self.name = name
        self.employee_id = employee_id
        super().__init__(**kwargs)

class RemoteWorker(Employee):
    def __init__(self, timezone, **kwargs):
        self.timezone = timezone
        super().__init__(**kwargs)

class TeamLead(Employee):
    def __init__(self, team, **kwargs):
        self.team = team
        super().__init__(**kwargs)

class EngineeringManager(RemoteWorker, TeamLead):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

engr_manager = EngineeringManager(
    name="Elena Wickman",
    employee_id=1001,
    timezone="US Mountain",
    team="Platform"
)

print(engr_manager.name)
print(engr_manager.employee_id)
print(engr_manager.timezone)
print(engr_manager.team)

# Expected result:
# Elena Wickman
# 1001
# US Mountain
# Platform

Endi engr_manager instance'imizda name, employee_id, timezone va team attribute'lari bor. Shuningdek, positional argument'lar o'rniga keyword argument'lardan foydalanayotganimizga e'tibor bering. Bu har bir initializer'ga o'ziga kerakli argument'larni olib, qolganlarini **kwargs orqali uzatish imkonini beradi.

Initialization jarayonida har bir sinf o'ziga tegishli argument'larni qabul qilib oladi va qolgan qiymatlarni MRO'dagi keyingi sinfga yuboradi. Masalan, RemoteWorker.__init__() timezone'ni aniq qabul qiladi. Python bu qiymatni timezone'ga bog'laydi va qolgan keyword argument'larni **kwargs'ga jamlaydi. To'liq zanjir quyidagicha:

  • EngineeringManager → hammasini uzatadi

  • RemoteWorker timezone'ni oladi → name, employee_id, team'ni uzatadi

  • TeamLead team'ni oladi → name, employee_id'ni uzatadi

  • Employee name, employee_id'ni oladi → bo'sh kwargs'ni uzatadi

  • object

Python'ning default object sinfi hech qanday argument qabul qilmaydi va shu tariqa initialization zanjirini yakunlaydi. Shu nuqtada ortib qolgan har qanday kutilmagan argument'lar TypeError'ga sabab bo'lishi mumkin, chunki object.__init__() ularni qabul qilmaydi.

Keng tarqalgan xatolar va ularni tuzatish usullari

Agar murakkab inheritance ierarxiyalari bilan hali ham qiynalayotgan bo'lsangiz, albatta, yolg'iz emassiz. Quyida eng keng tarqalgan tuzoqlardan ba'zilari va ulardan qanday qochish mumkinligi ko'rib chiqiladi.

super().__init__()'ni unutsangiz nima bo'ladi?

Agar subclass o'zining __init__()'ini aniqlasa-yu, super().__init__()'ni qo'shmasa, Python MRO'dagi keyingi __init__()'ni avtomatik ravishda chaqirmaydi. Subclass'ingiz instance'larini baribir yarata olishingiz mumkin, lekin ularda superclass'laringiz aniqlagan instance attribute'lari bo'lmasligi mumkin. Keyinroq o'sha attribute'lardan biriga murojaat qilmoqchi bo'lsangiz, AttributeError olasiz.

RemoteWorker uchun bu mana bunday ko'rinadi:

class Employee:
    def __init__(self, name, employee_id):
        self.name = name
        self.employee_id = employee_id

class RemoteWorker(Employee):
    def __init__(self, timezone):  
        self.timezone = timezone

worker = RemoteWorker("US Eastern")

print(worker.timezone)
print(worker.name)

# Expected result:
# US Eastern
# AttributeError: 'RemoteWorker' object has no attribute 'name'

Xodimning ismini olmoqchi bo'lganingizda Python uni topa olmaydi, chunki RemoteWorker.__init__() parent class'ning constructor'ini super().__init__() orqali chaqirmaydi. Bu muammoni hal qilish uchun super().__init__()'ni tegishli argument'lar bilan qaytadan qo'shing.

super().__init__()'da yetishmayotgan argument'lar

Subclass'ingizga super().__init__()'ni qo'shishni unutmagan bo'lishingiz mumkin, lekin baribir barcha kerakli argument'larni to'g'ridan-to'g'ri yoki **kwargs orqali aniq uzatishingiz kerak. super() funksiyasi __init__()'ga qaysi argument qiymatlarini yuborishni avtomatik ravishda taxmin qilmaydi.

Agar unutsangiz, mana bu sodir bo'ladi:

class Employee:
    def __init__(self, name, employee_id):
        self.name = name
        self.employee_id = employee_id

class RemoteWorker(Employee):
    def __init__(self, name, employee_id, timezone):  
        self.timezone = timezone
        super().__init__()

worker = RemoteWorker("Salvadore Russo", 5678, "US Eastern")

print(worker.name)

# Expected result:
# TypeError: Employee.__init__() missing 2 required positional arguments: 'name' and 'employee_id'

Bu muammoni tuzatish uchun kerakli argument'larni super().__init__(name, employee_id) bilan uzating yoki hamma joyda **kwargs'ga o'ting.

Parent class / child class o'rtasida kwargs nomuvofiqligi

Cooperative ko'p sinfli inheritance misolida ko'rganingizdek, har bir sinf o'zi kutgan keyword argument'larni qabul qilib oladi, qolgan argument'lar esa **kwargs orqali MRO bo'ylab uzatiladi. Ishlatilmagan har qanday argument **kwargs'da qoladi va oxir-oqibat object.__init__()'ga yetib boradi; biroq object.__init__() argument qabul qilmaydi, shuning uchun TypeError olasiz.

Yuqoridagi cooperative misolda aniqlangan sinflarni hisobga olsak, quyidagi kod xato beradi, chunki sinflarning hech birida email initialization argumenti yo'q:

engr_manager = EngineeringManager(
    name="Elena Wickman",
    employee_id=1001,
    timezone="US Mountain",
    team="Platform",
    email="ewickman@engineeringcompany.com"
)

# Expected result:
# TypeError: object.__init__() takes exactly one argument (the instance to initialize)

TypeError'dan qochish uchun siz bergan har bir keyword argument MRO'dagi initializer'lardan biri tomonidan qabul qilib olinishiga ishonch hosil qiling.

Python'ning super init'ini qachon chaqirmaslik kerak

Foydali bo'lishiga qaramay, to'g'ri Python kodi yozish uchun har bir subclass'da super().__init__() shart emas. Agar subclass'ingizga superclass'ingizdan hech qanday initialization kerak bo'lmasa, single inheritance'da u ortiqcha. Agar subclass'ingiz o'zining barcha initialization'ini o'zi bajarsa, super().__init__()'dan voz kechishingiz mumkin. Shuningdek, sinfingiz umuman boshqa sinflarga asoslanmagan bo'lsa ham u sizga kerak emas. Oxir-oqibat, subclass'ingizni to'g'ri initialization qilish uchun MRO'ning boshqa joyidagi initialization'ni ishga tushirish kerak bo'lganda super().__init__()'dan foydalaning.

Xulosa

__init__() method'i Python sinfining instance'ini initialization qilishda attribute'larni o'rnatishga yordam beradi; super() esa chaqiruvlarni inheritance ierarxiyangizdagi boshqa sinflarga uzatish imkonini beradigan funksiya. Ular birgalikda inheritance ierarxiyasi bo'ylab initialization'ni muvofiqlashtirish usulini taqdim etadi. Oddiy inheritance'da super() method'ga to'g'ridan-to'g'ri parent class'dan murojaat qilishi mumkin, ammo multiple inheritance'ga ega sinflarni loyihalash va ular bilan ishlashda MRO'ni yodda tuting. Cooperative method'lar va **kwargs'dan foydalanganda har bir argument biror sinf tomonidan qabul qilib olinishi kerak; aks holda Python TypeError ko'taradi.

Yangi super() bilimlaringizni sinab ko'rmoqchimisiz? AI Tutor'dan siz uchun quiz tuzib berishini so'rang. Boshlash uchun foydalanishingiz mumkin bo'lgan prompt:

Yo'l xaritalariQo'llanmalarFAQYouTube

yo'lxaritaroadmap.shasosida

Hamjamiyat tomonidan yaratilgan yo'l xaritalari, eng yaxshi amaliyotlar, loyihalar, maqolalar, manbalar va yo'nalishlar — o'z yo'lingizni tanlash va kasbingizda o'sish uchun.

© yo'lxarita·Shartlar·Maxfiylik·

roadmap.sh

Barcha kontent roadmap.sh loyihasidan olingan (© Kamran Ahmed) va shaxsiy o'rganish uchun o'zbek tiliga tarjima qilinmoqda.

Qidiruv

Yo'l xaritalari, loyihalar va savollarni qidiring