ProgramlamaFullstack Python geliştirici

Python'da dizilerin ve sözlükların unpacking'inde * ve ** operatörlerinin nasıl çalıştığını açıklayın. İnce noktalar nelerdir ve bu nerelerde yararlıdır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Soru geçmişi:

Unpacking için * ve ** operatörleri Python'da uzun zamandır var ama her sürümle birlikte kullanımları genişledi (örneğin, Python 3.5 ile birlikte birkaç koleksiyonu * ve ** ile birleştirme desteği eklendi). Bu operatörler, koleksiyonlarla çalışmayı daha esnek hale getirir, özellikle de argümanları geçirme ve fonksiyonlarda toplama sırasında.

Sorun:

Dizilerle, değişken sayıda argüman içeren parametrelerin geçişinde unpacking olmadan çalışırken, koleksiyonların boyutunu kontrol etmek ve döngüler yazmak zorunluluğu ortaya çıkıyor. Yanlış kullanım bu operatörlerin karıştırılmasında kolay hatalara neden olabilir.

Çözüm:

* operatörü dizilerin (list, tuple, set) unpacking'i için, ** operatörü ise fonksiyonları çağırırken veya birkaç sözlüğü birleştirirken sözlüklerin unpacking'i için tasarlanmıştır. Argümanları zarif bir şekilde iletmeyi, koleksiyonları birleştirmeyi ve rastgele yapıları fonksiyon parametrelerine kolayca dönüştürmeyi sağlar.

Kod örneği:

def foo(a, b, c): print(a, b, c) args = (1, 2, 3) foo(*args) # 1 2 3 params = {'a': 10, 'b': 20, 'c': 30} foo(**params) # 10 20 30 list1 = [1, 2] list2 = [3, 4] combined = [*list1, *list2] print(combined) # [1, 2, 3, 4]

Anahtar özellikler:

  • *sequence, elemanları ayrı pozisyonel argümanlar olarak geçirirken, **dict isimli argümanlar olarak geçirir.
  • [*a, *b] ve {**d1, **d2} ile koleksiyonları şık bir şekilde birleştirme ve kopyalama yapabilirsiniz.
  • Unpacking hem fonksiyon tanımında/ bildiriminde hem de çağrılarda kullanılır.

Kandırıcı sorular.

*** ve 'yi karmaşık koleksiyonlar için kullanabilir miyiz?

Fonksiyon çağrısında * yalnızca pozisyonel argümanlarla, ** ise yalnızca isimli argümanlarla çalışır. Ayrıştırılmamış bir dict * veya bir dizi ** olarak geçtiğinde hata ortaya çıkar.

def foo(a, b): print(a, b) foo(*{'a': 1, 'b': 2}) # Çıktı: a b (sözlüğün anahtarları, değerleri değil!)

**{**d1, d2} ile dict birleştirirken anahtar isimleri kesişirse ne olur?

Sonuçta bu anahtara sahip son sözlüğün değeri olacak.

d1 = {'x': 1, 'y': 2} d2 = {'y': 33, 'z': 44} merged = {**d1, **d2} print(merged) # {'x': 1, 'y': 33, 'z': 44}

List comprehension veya dict comprehension içinde * ve ** kullanabilir miyiz?

Evet, Python 3.5 itibarıyla bu geçerlidir. Örneğin:

lst = [1, 2, *range(3, 6)] # [1, 2, 3, 4, 5] dct = {**{'a': 1}, 'b': 2, **{'c': 3}}

Yaygın hatalar ve anti-patternler

  • * ile dict geçişi (yalnızca anahtarlar unpack edilir).
  • İsimli argümanların aşırı kesişmesi TypeError'a neden olabilir.
  • Mapping olmayan bir nesne için ** kullanmaya çalışmak.

Hayattan bir örnek

Olumsuz durum

Bir geliştirici, işlevine bir dict alır ve onu * ile ayrıştırır yerine ** kullanmaz. Beklenmeyen bir davranış ortaya çıkar: işlevine değerler değil, anahtarlar gelir.

Artılar:

Hata kodu hemen çökmez, “çalışıyor” gibi görünür.

Eksiler:

Gizli hatalar ve beklenen mantığa uyumsuzluk.

Olumlu durum

Parametrelerin doğru bir şekilde **kwargs ile geçirilmesi, sözlüklerin düzgün birleştirilmesi, * kullanarak dinamik dizi birleştirilmesi.

Artılar:

Maksimum esneklik, kodun sadeliği, yeniden yapılandırma kolaylığı.

Eksiler:

Büyük sayıda parametre ve koleksiyonlar ile çalışırken, isimlere ve sıraya dikkat etmek önemlidir, aksi halde hatalar ortaya çıkabilir.