Skip to content

To'plamlarni o'zgaruvchilarga ochib berish (unpacking).

Unpacking iterable(list, tuple, dict, set) tur qiymatlarini ochib, bir vaqtning o'zida bir nechta o'zgaruvchilarga tayinlash imkonini beradi. Oddiy qilib aytganda bir nechta qiymatni bitta to'plamdan olib, bir nechta o'zgaruvchiga joylash. Quyida birinchi oddiy misol bilan ko'ramiz:

unpacking.py
1
2
3
4
5
6
7
numbers = [1, 2, 3]

a, b, c = numbers

print(a)
print(b)
print(c)

Natija

1
2
3

Bu yerda numbers ichidagi elementlar a, b, c larga unpack(ochib berish) qilindi. Odatda eng ko'p tuple bilan ishlatiladi.

unpacking.py
1
2
3
4
5
6
point = (10, 20)

x, y = point

print(x)
print(y)

Natija

10
20

Pythonda funksiyalar bir nechta qiymat qaytara oladi(tuple turida). Bu imkoniyat kod yozish jarayonida ko'p hollarda kodni sifatli va mantiqiy qismlarni yozishni osonlashtiradi. Quyidagi misolda funksiyadan qaytgan qiymatlarni unpack qilishni ko'ramiz:

get_user_unpack.py
1
2
3
4
def get_user():
    return "Ali", 25

name, age = get_user()

Bu misolda natija name = "Ali", age = 25 ko'rinishida bo'ladi.


Bizda shunday holatlar bo'lishi mumkin to'plamda nechta element bo'lishi aniq bo'lmaydi bunday holatlarda unpacking ishlatilsa quyidagicha xatolik sodir bo'ladi:

get_user_unpack.py
1
2
3
4
def get_user():
    return "Ali", 25, "Toshkent shahri"

name, age = get_user()

Natija:

ValueError: too many values to unpack (expected 2)

Bunday holatlar uchun Catch-all unpacking deb nomlangan usul mavjud bo'lib, agar qiymatlar soni aniq bo'lmasa unpack qilishda asosiy belgilangan qiymatlar olinadi qolganlari esa ro'yxat(list)da saqlanadi.

Catch-all unpacking:

get_user_unpack.py
1
2
3
4
5
6
def get_user():
    return "Ali", 25, "Toshkent shahri", "Amir Temur shoh koʻchasi"

name, age, *data = get_user()

print(name, age, data)

Natija:

Ali 25 ['Toshkent shahri', 'Amir Temur shoh koʻchasi']

Yulduzcha (*) operatori qolgan barcha elementlarni bitta o'zgaruvchida ro'yxat ko'rinishida saqlaydi. Elementlar soni noma'lum bo'lgan to'plamlarda bu imkoniyat bilan ishlash foydali bo'ladi. Agar elementlar soni kam bo'lib qolgan taqdirda ham bu imkoniyat ishlaydi faqat bu yerda [] bo'sh ro'yxat bo'ladi.

Keling yana bir misolni ko'ramiz. Tasavvur qiling talabalar baholarini qayta ishlaydigan funksiyamiz bor. Talabalar bir nechta test natijalariga ega. Biz birinchi va ikkinchi o'rindagilarni alohida ajratib, qolganlarini bir joyga yig'moqchimiz. Bu quyidagicha amalga oshiriladi:

get_user_unpack.py
1
2
3
4
5
6
7
scores = [88, 92, 79, 85, 90]

first, second, *others = scores

print("Birinchi:", first)
print("Ikkinchi:", second)
print("Qolganlar:", others)

Bu yondashuv kodni soddalashtiradi va indexdan yoki murakkab sikllardan foydalanishga ehtiyoj qoldirmaydi.

Endi yana bir holatni ko'rib chiqamiz. Bizga faqat talabalar ichida birinchi va oxirgi o'rindagilari kerak, qolganlari esa kerak emas. Eski Python(python < 3) kodlarida bu odatda indekslash va slicing orqali amalga oshirilgan. Ammo catch-all unpacking yordamida buni ancha ixcham yozish mumkin.

get_user_unpack.py
1
2
3
4
5
6
scores = [88, 92, 79, 85, 90]

first, *_, last  = scores

print("Birinchi:", first)
print("Oxirgi:", last)

Bu yerda _ (underscore) o'zgaruvchi nomi sifatida ishlatiladi, Pythonda bu qiymat "muhim emas" yoki kerak emas degan ma'noni bildiradi.


Endi catch-all unpacking funksiya argumentida qanday ishlatilishini ko'ramiz. Pythonda funksiyalar *args orqali noma'lum uzunlikdagi argumentlarni qabul qilish mumkin. Bu yerda *args kabi parametrlar qo'shimcha argumentlarni tuple to'plamida saqlaydi, bu funksiyani moslashuvchan qiladi.

unpacking.py
1
2
3
4
5
def print_messages(*args):
    for arg in args:
        print(arg)

print_messages(1, 2, 3)

Bu yerda tuple turi ustida amallar bajariladi.

Agar funksiya argumentlari nomlangan bo'lsa, **kwargs ko'rinishida argument e'lon qilinadi. Berilgan argumentlar dict ko'rinishida saqlanadi.

unpacking.py
1
2
3
4
5
def user_info(**kwargs):
    print(kwargs)
    print(type(kwargs))

user_info(name="Suxrob", age=25, city="Toshkent")

Bu yerdagi qiymat bilan ishlaganda dict ustida amallar bajariladi.


Info

  • *args ko'p oddiy argumentlar uchun.
  • **kwargs ko'p nomli argumentlar uchun.

Tip

args va kwargs aynan shu nomlar bo'lishi shart emas. Nomlash boshqacha bo'lishi mumkin:

def test(*numbers, **user_data):
    pass
*args va **kwargs ko'rinishida nomlash standart bo'lgani uchun shunday nomlash tavfsiya etiladi.


Funksiyaga argumentlar berishda tartibiga e'tibor berish juda muhim. Agar e'tibor berilmasa SyntaxError sodir bo'ladi.

unpacking.py
def funksiya(normal, default=None, *args, keyword_only=None, **kwargs):
    pass

Bu yerda parametrlar quyidagi ketma-ketlikda bo'ladi:

  1. Oddiy parametrlar.
  2. Boshlang'ich qiymatli parametrlar
  3. *args
  4. Nomlangan parametrlar
  5. **kwargs

Info

Boshlang'ich qiymatli parametrlar oddiy parametrdan oldin kelolmaydi.

xato
def user(age=18, name):
    pass

Qisqa qilib aytganda, * va ** operatorlari Pythonning kuchli imkoniyati bo'lib, ular yordamida kod yanada ixcham, moslashuvchan va samarali bo'ladi.