Python'da tuple (demet), oluşturulduktan sonra değiştirilemeyen (immutable) sıralı bir veri yapısıdır. Virgülle ayrılmış değerlerle yazılır: nokta = (3, 4) ya da parantezsiz nokta = 3, 4. Tuple'ı tuple yapan parantez değil virgüldür; tek elemanlı bir tuple için ('elma',) şeklinde sonda virgül gerekir. Unpacking (açma) ise bir tuple'ın ya da herhangi bir yinelenebilirin elemanlarını tek satırda ayrı değişkenlere dağıtmaktır: x, y = nokta.

Bu yazıda tuple oluşturmanın kurallarını, değiştirilemezliğin gerçekte neyi kapsadığını, tuple'ların neden sözlük anahtarı olabildiğini, yıldızlı atamayı (ilk, *kalan = ...), iç içe açmayı ve sık karşılaşılan ValueError mesajlarını Python 3.15.2 ile çalıştırılmış örneklerle anlatıyoruz. Listelerle ilgili her şey için liste metotları yazısına, öğrenme sırasının tamamı için Python öğrenme rehberi sayfasına bakabilirsiniz.

Tuple nasıl oluşturulur?

Resmî belgeler tuple oluşturmanın dört yolunu sayar: boş tuple için boş parantez (), tek elemanlı tuple için sonda virgül (a, veya (a,)), birden fazla eleman için virgülle ayırma (a, b, c veya (a, b, c)) ve herhangi bir yinelenebilirden tuple kuran tuple() yapıcısı. Belgelerin vurguladığı nokta şu: parantezler yalnızca boş tuple'da ve söz dizimi belirsizliğini önlemek gerektiğinde zorunludur. Örneğin f(a, b, c) üç argümanlı bir fonksiyon çağrısıdır, f((a, b, c)) ise tek argüman olarak üç elemanlı bir tuple gönderir.

python
koordinat = (41.0, 28.9)
renk = 255, 128, 0            # parantez şart değil
bos = ()
tek = ('elma',)
tek_degil = ('elma')          # bu sadece parantez içinde bir string

print(type(renk))             # çıktı: <class 'tuple'>
print(len(bos), len(tek))     # çıktı: 0 1
print(tek)                    # çıktı: ('elma',)
print(type(tek_degil))        # çıktı: <class 'str'>
print(tuple('abc'))           # çıktı: ('a', 'b', 'c')
print(tuple([1, 2, 3]))       # çıktı: (1, 2, 3)

Tek elemanlı tuple'daki virgülü unutmak en yaygın hatadır. ('elma') yazdığınızda parantezler yalnızca gruplama işlevi görür ve elinizde bir string kalır. Python tuple'ları ekrana yazarken her zaman parantez kullanır ki iç içe tuple'lar doğru okunabilsin; tek elemanlı bir tuple'ı da sonundaki virgülle gösterir. tuple() yapıcısına zaten bir tuple verirseniz belgelere göre aynı nesne değişmeden geri döner, yeni bir kopya oluşturulmaz.

Değiştirilemezlik gerçekte ne demek?

Bir tuple oluşturulduktan sonra elemanlarına yeni değer atayamaz, eleman ekleyemez ya da silemezsiniz. Ancak bu kural tuple'ın kendi yuvaları için geçerlidir: tuple içinde bir liste gibi değiştirilebilir bir nesne varsa, o nesnenin içeriği değişebilir. Tuple yalnızca "hangi nesneleri gösterdiğini" sabitler, gösterdiği nesnelerin kendisini dondurmaz.

python
t = (12345, 54321, 'merhaba')
try:
    t[0] = 88888
except TypeError as hata:
    print(hata)    # çıktı: 'tuple' object does not support item assignment

v = ([1, 2, 3], [3, 2, 1])
v[0].append(4)
print(v)           # çıktı: ([1, 2, 3, 4], [3, 2, 1])

Bu ayrımın en şaşırtıcı sonucu Python SSS'de ayrıca anlatılır: içinde liste olan bir tuple elemanına += uygularsanız hata alırsınız ama liste yine de genişlemiş olur. Sebebi, listelerde += işleminin önce listenin __iadd__() metodunu çağırması (bu adım listeyi yerinde genişletir) ve ardından sonucu tuple'ın ilgili yuvasına geri atamaya çalışmasıdır. Atama adımı tuple değiştirilemez olduğu için başarısız olur, ama genişletme çoktan gerçekleşmiştir.

python
t = (['foo'], 'bar')
try:
    t[0] += ['item']
except TypeError as hata:
    print(hata)   # çıktı: 'tuple' object does not support item assignment
print(t)          # çıktı: (['foo', 'item'], 'bar')

# Hata almadan aynı işi yapmanın yolu metodu doğrudan çağırmaktır:
t[0].extend(['ikinci'])
print(t)          # çıktı: (['foo', 'item', 'ikinci'], 'bar')

Tuple işlemleri ve iki metodu

Tuple'lar ortak dizi işlemlerinin hepsini destekler: indeksleme, dilimleme, in ile üyelik testi, + ile birleştirme, * ile tekrarlama, len(), min(), max(). Değiştirme metotları olmadığı için yalnızca iki metodu vardır: count() ve index(). Birleştirme ve dilimleme her zaman yeni bir tuple üretir. sorted() ise girdinin tipi ne olursa olsun bir liste döndürür; sonucu tuple olarak istiyorsanız tuple(sorted(t)) yazmanız gerekir.

python
t = (3, 1, 4, 1, 5, 9)
print(t[1], t[-1], t[1:4])     # çıktı: 1 9 (1, 4, 1)
print(t.count(1), t.index(4))  # çıktı: 2 2
print(t + (2, 6))              # çıktı: (3, 1, 4, 1, 5, 9, 2, 6)
print(('a',) * 3)              # çıktı: ('a', 'a', 'a')
print(5 in t)                  # çıktı: True
print(sorted(t))               # çıktı: [1, 1, 3, 4, 5, 9]
print(tuple(sorted(t)))        # çıktı: (1, 1, 3, 4, 5, 9)

Tuple mı liste mi?

Tuple mı liste mi? Değiştirilebilir mi, Söz dizimi, Tek eleman, Metotlar

Python SSS'deki tasarım açıklamasına göre ikisi benzer görünse de farklı amaçlarla kullanılır. Tuple'lar Pascal'daki kayıtlara ya da C'deki struct'lara benzer: farklı tiplerde olabilen, birbiriyle ilişkili, az sayıda veriyi bir grup olarak taşır. Bir koordinat, bir tarih parçası (yıl, ay, gün) ya da bir veritabanı satırı tipik örneklerdir. Listeler ise diğer dillerdeki dizilere benzer: genellikle aynı türden, sayısı değişebilen nesneleri tutar ve elemanlar tek tek işlenir. Tuple'lara çoğunlukla açma (unpacking) ya da indeksle, listelere döngüyle erişilir.

Özelliktuplelist
Değiştirilebilir miHayırEvet
Söz dizimi(1, 2) veya 1, 2[1, 2]
Tek eleman(1,)[1]
Metotlarcount, indexappend, extend, insert, remove, pop, sort ve diğerleri
Hash edilebilir miElemanları hash edilebiliyorsa evetHayır
Sözlük anahtarı veya küme elemanıOlabilir (aynı koşulla)Olamaz
Tipik kullanımSabit yapılı, farklı tipli kayıtAynı tipli, uzunluğu değişen koleksiyon

Hash edilebilirlik ve sözlük anahtarı olarak tuple

Hash edilebilirlik ve sözlük anahtarı olarak tuple

Değiştirilemez dizilerin değiştirilebilir dizilerde olmayan tek ortak yeteneği hash() desteğidir. Bu sayede tuple'lar sözlük anahtarı olarak ve kümelerde eleman olarak kullanılabilir. Koşul şudur: tuple'ın tüm elemanları da hash edilebilir olmalıdır. İçinde liste bulunan bir tuple'ın hash'ini almaya çalışırsanız TypeError alırsınız. Python SSS, bir listeyi sözlük anahtarı olarak kullanmak istediğinizde önce tuple(liste) ile tuple'a çevirmenizi önerir.

python
tahta = {(0, 0): 'kale', (0, 1): 'at', (7, 4): 'şah'}
print(tahta[(0, 1)])                  # çıktı: at
print(tahta.get((5, 5), 'boş'))       # çıktı: boş
print(hash((1, 2)) == hash((1, 2)))   # çıktı: True

try:
    hash(([1], 2))
except TypeError as hata:
    print(hata)    # çıktı: unhashable type: 'list'

try:
    {[0, 0]: 'kale'}
except TypeError as hata:
    print(hata)    # çıktı: cannot use 'list' as a dict key (unhashable type: 'list')

konum = [0, 0]
print(tahta[tuple(konum)])            # çıktı: kale

Hash edilebilirlik kavramının ayrıntısı ve kümelerle ilişkisi set ve küme işlemleri, sözlük anahtarı kuralları ise sözlük metotları yazısında anlatılıyor.

Packing ve unpacking

t = 12345, 54321, 'merhaba' ifadesine belgelerde tuple packing (paketleme) denir: üç değer tek bir tuple'a paketlenir. Tersi olan sequence unpacking (dizi açma) ise sağdaki dizinin elemanlarını soldaki isimlere dağıtır. Açma yalnızca tuple ile sınırlı değildir; sağ tarafta liste, string, range ya da herhangi bir yinelenebilir olabilir. Belgelerin belirttiği gibi çoklu atama (a, b = 1, 2) aslında paketleme ile açmanın birleşimidir. İki değişkenin değerini geçici değişken kullanmadan değiştirmek de buradan gelir: sağ taraf önce tamamen hesaplanıp bir tuple'a paketlenir, sonra sola açılır.

python
t = 12345, 54321, 'merhaba'
x, y, z = t
print(x, z)        # çıktı: 12345 merhaba

a, b = 1, 2
a, b = b, a
print(a, b)        # çıktı: 2 1

ad, soyad = 'Ada Lovelace'.split()
print(soyad)       # çıktı: Lovelace

bolum, kalan = divmod(17, 5)
print(bolum, kalan)  # çıktı: 3 2

Yıldızsız açmada soldaki isim sayısı ile sağdaki eleman sayısı tam olarak eşleşmelidir. Eşleşmezse ValueError alırsınız ve Python mesajda kaç değer beklediğini ve kaç değer bulduğunu söyler. Bu mesajı okumak, özellikle bir fonksiyonun beklediğinizden farklı sayıda değer döndürdüğü durumlarda hatayı hızla bulmanızı sağlar.

python
nokta = (3, 4, 5)
try:
    x, y = nokta
except ValueError as hata:
    print(hata)   # çıktı: too many values to unpack (expected 2, got 3)

try:
    x, y, z, w = nokta
except ValueError as hata:
    print(hata)   # çıktı: not enough values to unpack (expected 4, got 3)

Yıldızlı atama: ilk, *kalan = ...

Sol taraftaki isimlerden birinin başına yıldız koyarsanız (belgelerde "starred target"), Python önce yıldızsız isimleri baştan ve sondan doldurur, arta kalan tüm elemanları ise bir liste olarak yıldızlı isme verir. Bu liste boş da olabilir. Sağ taraf bir tuple bile olsa yıldızlı hedef her zaman liste alır. Bir atamada yalnızca bir yıldızlı hedef olabilir; ikinci bir yıldız söz dizimi hatasıdır, çünkü elemanların nasıl bölüneceği belirsiz kalır. Kullanmayacağınız kısımlar için *_ yazmak yaygın bir alışkanlıktır.

python
ilk, *orta, son = [1, 2, 3, 4, 5]
print(ilk, orta, son)    # çıktı: 1 [2, 3, 4] 5

bas, *kalan = 'python'
print(bas, kalan)        # çıktı: p ['y', 't', 'h', 'o', 'n']

*_, sonuncu = (10, 20, 30)
print(sonuncu)           # çıktı: 30

a, *b = (1,)
print(a, b)              # çıktı: 1 []

try:
    a, b, *c, d, e = (1, 2)
except ValueError as hata:
    print(hata)          # çıktı: not enough values to unpack (expected at least 4, got 2)

try:
    compile('a, *b, *c = range(5)', 'ornek', 'exec')
except SyntaxError as hata:
    print(hata.msg)      # çıktı: multiple starred expressions in assignment

İç içe açma ve döngülerde unpacking

Açma özyinelemelidir: soldaki hedef listesinde parantezle yeni bir grup açarsanız, sağdaki karşılık gelen eleman da ayrıca açılır. Bu özellik en çok for döngülerinde işe yarar, çünkü döngü değişkeni de bir atama hedefidir. enumerate() ve dict.items() her adımda iki elemanlı tuple'lar üretir; bunları döngü başlığında doğrudan iki isme açmak Python'da standart yazım biçimidir. zip() de birden çok diziyi aynı anda dolaşırken her adımda bir tuple verir.

python
kayitlar = [('Ayşe', (17, 'B')), ('Can', (15, 'A'))]
for ad, (yas, sinif) in kayitlar:
    print(ad, yas, sinif)
# çıktı: Ayşe 17 B
# çıktı: Can 15 A

stok = {'kalem': 40, 'defter': 12}
for urun, adet in stok.items():
    print(f'{urun}: {adet}')
# çıktı: kalem: 40
# çıktı: defter: 12

for sira, (urun, adet) in enumerate(stok.items(), start=1):
    print(sira, urun, adet)
# çıktı: 1 kalem 40
# çıktı: 2 defter 12

Açma yalnızca atama hedeflerinde değil, değer üretirken de kullanılır. Bir liste, tuple veya küme yazarken bir ifadenin başına * koyarsanız o ifadenin elemanları yerinde açılır. Fonksiyon çağrısında f(*t) de tuple'ın elemanlarını ayrı argümanlar olarak gönderir. Fonksiyon tanımındaki *args ve çağrıdaki açmanın tüm kuralları *args, **kwargs ve parametreler yazısında.

python
x = [1, 2, 3]
print((0, *x, 4))     # çıktı: (0, 1, 2, 3, 4)
print([*x, *'ab'])    # çıktı: [1, 2, 3, 'a', 'b']

def alan(en, boy):
    return en * boy

olcu = (3, 4)
print(alan(*olcu))    # çıktı: 12

Fonksiyondan birden fazla değer döndürmek

Python'da bir fonksiyon teknik olarak tek bir nesne döndürür; return a, b yazdığınızda döndürülen nesne bir tuple'dır. Çağıran taraf bu tuple'ı tek değişkende tutabilir ya da hemen açabilir. Bu desen divmod() gibi yerleşik fonksiyonlarda da kullanılır. Döndürülen alan sayısı artıp anlamları karışmaya başladığında, alanlara isimle erişilen bir yapıya geçmek kodu daha okunaklı kılar.

python
def min_max(sayilar):
    return min(sayilar), max(sayilar)

sonuc = min_max([7, 2, 9])
print(sonuc, type(sonuc).__name__)   # çıktı: (2, 9) tuple

enkucuk, enbuyuk = min_max([7, 2, 9])
print(enbuyuk - enkucuk)             # çıktı: 7

Tuple karşılaştırma ve sıralama

Aynı tipteki diziler sözlük sırasıyla karşılaştırılır: ilk elemanlar karşılaştırılır, eşitlerse ikincilere geçilir ve böyle devam eder. Bir tuple diğerinin başlangıç kısmıysa kısa olan küçük sayılır. Bu kural tuple'ları çok kriterli sıralama için çok kullanışlı kılar ve sürüm numarası gibi parçalı değerleri karşılaştırmayı kolaylaştırır. Eşitlik testinde tuple ile liste farklı tipler olduğundan (1, 2) == [1, 2] sonucu False'tur.

python
print((1, 2, 3) < (1, 2, 4))       # çıktı: True
print((1, 2, 3, 4) < (1, 2, 4))    # çıktı: True
print((1, 2) < (1, 2, -1))         # çıktı: True
print((3, 15, 2) >= (3, 10))       # çıktı: True
print((1, 2) == [1, 2])            # çıktı: False

sonuclar = [('Can', 72), ('Ayşe', 91), ('Ece', 72)]
# Puana göre azalan, eşitlikte isme göre artan:
print(sorted(sonuclar, key=lambda s: (-s[1], s[0])))
# çıktı: [('Ayşe', 91), ('Can', 72), ('Ece', 72)]

Atamada sıra tuzağı

Belgelerdeki bir uyarı, açmanın "eşzamanlı" görünmesine rağmen sol taraftaki hedeflerin soldan sağa sırayla atandığını hatırlatır. Sol tarafta hem bir indeks değişkeni hem de o indeksi kullanan bir hedef varsa, ikinci hedef ilk atamadan sonraki yeni indeks değerini kullanır. Aşağıdaki örnekte önce i 1 olur, ardından x[1] güncellenir; bu yüzden sonuç [0, 2]'dir.

python
x = [0, 1]
i = 0
i, x[i] = 1, 2
print(x)    # çıktı: [0, 2]

İsimli alanlar: namedtuple'a kısa bakış

Bir tuple'ın konumlarının ne anlama geldiğini hatırlamak zorlaştığında collections.namedtuple() her konuma bir isim verir. Ortaya çıkan nesne yine bir tuple'dır: indekslenebilir, açılabilir, hash edilebilir. Ek olarak alanlara p.x gibi isimle ulaşılır ve ekrana okunaklı biçimde yazılır. Belgelere göre isimli tuple örneklerinin örnek başına sözlüğü olmadığı için normal tuple'lardan fazla bellek kullanmazlar. _replace(), _asdict() ve varsayılan değerler gibi ayrıntılar collections modülü yazısında, tip notlu sürümü olan typing.NamedTuple ise type hints yazısında anlatılıyor.

python
from collections import namedtuple

Nokta = namedtuple('Nokta', ['x', 'y'])
p = Nokta(3, 4)
print(p)               # çıktı: Nokta(x=3, y=4)
print(p.x + p.y, p[0]) # çıktı: 7 3
x, y = p
print(isinstance(p, tuple))   # çıktı: True

Python 3.15 ile tuple'dan türetilen sınıflarda (namedtuple() ile oluşturulanlar dahil) herhangi bir __slots__ tanımlamaya izin verildi; bu, kendi tuple alt sınıflarını yazanları ilgilendiren küçük bir dil değişikliğidir. Sınıf tabanlı, değiştirilebilir kayıtlar için ise dataclasses daha uygun bir araçtır.

Sık yapılan hatalar

Sık yapılan hatalar: Tek elemanlı tuple'da virgülü unutmak, Tuple'a append() çağırmak. Tuple'ın değiştirme metodu yoktur; eleman eklemek..., Değiştirilemezliği "derin" sanmak...
  • Tek elemanlı tuple'da virgülü unutmak: ('a') bir stringdir, ('a',) tuple'dır.
  • Tuple'a append() çağırmak. Tuple'ın değiştirme metodu yoktur; eleman eklemek için yeni tuple oluşturun ya da liste kullanın.
  • Değiştirilemezliği "derin" sanmak: tuple içindeki liste değişebilir ve böyle bir tuple hash edilemez.
  • Açmada isim sayısını yanlış tutturmak: ValueError mesajındaki "expected" ve "got" değerlerine bakın.
  • Yıldızlı hedefin tuple döndürdüğünü sanmak: yıldızlı isim her zaman liste alır.
  • sorted(t) sonucunu tuple sanmak: sonuç listedir.
  • Tuple'ları is ile karşılaştırmak: belgelere göre aynı değerli iki tuple aynı nesne olabilir de olmayabilir de; değer karşılaştırması için == kullanın.

Python 3.15'te değiştirilebilir bir tipe ait metodu değiştirilemez bir tipte çağırdığınızda hata mesajı size değiştirilebilir karşılığı önerir. Aşağıdaki çıktı Python 3.15.2'den alınmıştır, yalnızca dosya yolunu ornek.py olarak kısalttık. Diğer yenilikler için Python 3.15 yenilikleri, hata mesajlarının genel okunuşu için sık görülen hata mesajları yazılarına bakabilirsiniz.

python
koordinat = (41, 29)
koordinat.append(10)
# Traceback (most recent call last):
#   File "ornek.py", line 2, in <module>
#     koordinat.append(10)
#     ^^^^^^^^^^^^^^^^
# AttributeError: 'tuple' object has no attribute 'append'. Did you mean to use a 'list' object?

Sık Sorulan Sorular

Tuple listeden daha mı hızlı?

Resmî belgeler tuple ile liste arasında genel bir hız karşılaştırması vermez; seçimi performansa değil amaca göre yapmanızı önerir. Belgelerin net olarak söylediği şey şudur: tuple değiştirilemez ve elemanları uygunsa hash edilebilir, bu yüzden sözlük anahtarı ve küme elemanı olabilir; liste ise değiştirilebilir ve bu iki yerde kullanılamaz.

Bir tuple'ı nasıl "değiştiririm"?

Değiştiremezsiniz, ama istediğiniz içerikte yeni bir tuple oluşturabilirsiniz: t = t[:1] + (99,) + t[2:]. Çok sayıda değişiklik yapacaksanız list(t) ile listeye çevirip işlemleri yapın, sonra tuple() ile geri dönün. İsimli tuple'larda _replace() aynı işi alan adıyla yapar.

Parantezsiz tuple ne zaman sorun çıkarır?

Tuple daha büyük bir ifadenin parçası olduğunda parantez gerekir. Fonksiyon argümanlarında, return dışındaki karmaşık ifadelerde ve comprehension içinde bir tuple üretirken parantez yazmazsanız ifade farklı yorumlanır ya da söz dizimi hatası alırsınız; comprehension örneği list comprehension yazısında.

match deyimi tuple'larla nasıl çalışır?

match deyimindeki dizi desenleri (case (x, y):, case (ilk, *kalan):) burada anlattığımız açma mantığının desen eşleştirmeye uyarlanmış halidir. Ayrıntılar match-case desen eşleştirme yazısında.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Python öğrenme rehberi · Liste metotları · Sözlük metotları · *args ve **kwargs · collections ve namedtuple · match-case