Walrus Operator

3.8 güncellemesiyle gelen Walrus operatörü nedir?

Anladığım kadarıyla bir fonksiyonu iki kere çağırmaktan kurtaran bir özellik o. Bir örnek yapayım izninizle:

f = lambda x: x ** 3
print([f(x) for x in range(10) if f(x) in [1, 8, 27]])
# [1, 8, 27]

Bu yukarıdaki ifadede f(x) fonksiyonu aynı satırda iki kez çağrılmış oluyor. Bunu önlemek için walrus operatörü kullanılıyor yanılmıyorsam.

f = lambda x: x ** 3
print([fx for x in range(10) if (fx := f(x)) in [1, 8, 27]])
# [1, 8, 27]

f(x) fonksiyonunu bir satırda iki kere kullanmayı önlemek için şöyle de yapılabilir.

f = lambda x: x ** 3
print(list(filter(lambda i: i in [1, 8, 27], [f(x) for x in range(10)])))
# [1, 8, 27]

Bir degiskene deger atayan expression yaratmaya yarayan operator. = operatorunun degerini donduren versiyonu.

Anlamadım. Daha basit anlatabilir misiniz?

Mesela aşağıdaki örneğe bakalım:

f = lambda x: x ** 3

Yukarıda f isimli bir lambda fonksiyonu var. Bu fonksiyonu f(10) şeklinde çağırırsak, bize 10 sayısının küpünü verecektir.

Şimdi şöyle bir program yazmamız gerekiyor olsun: 1’den 10’a kadar olan sayıların küpleri hesaplansın ve küpü 30’dan küçük olan sayılar ekrana yazdırılsın. Bunun için şöyle bir yol izleyebiliriz.

f = lambda x: x ** 3
print([f(x) for x in range(10) if f(x) < 30])

Bu yukarıdaki kodlar [0, 1, 8, 27] listesini geri döndürecektir. Yani amacımıza uyan bir kod yazmışız. Ancak, burada dikkatinizi yukarıdaki kodlara verin lütfen. f(x) fonksiyonunun aynı satırda (ikinci satırda) iki kere çağrıldığını görüyorsunuz.

Walrus operatörünü kullandığımızda, f(x) fonksiyonunu aynı satırda iki kez kullanmamış oluruz. Bu da bizim işlem sayımızı azaltır. Eğer f(x) pahalıya mal olan bir fonksiyon ise, onu aynı satırda iki kere çağırmak istemeyiz herhalde. İşte böyle durumlarda Walrus operatörü kullanılır. Mesela yukarıdaki örneği bir de walrus operatörü kullanarak yeniden yazalım:

f = lambda x: x ** 3
print([fx for x in range(10) if (fx := f(x)) < 30])

Burada fx, f(x) fonksiyonundan dönen değerin yerine geçer. İsminin fx olması gerekmiyor. İsterseniz y yazın. Walrus operatörünün gösterimi şu şekildedir: (fx := f(x))

İlk mesajda size üçüncü bir yoldan daha bahsetmiştim. f(x) fonksiyonunu aynı satırda iki kere kullanmadığımız başka bir yol da izleyebiliriz. Walrus operatörü Python’a eklenmeden önce bu yol bizim bir fonksiyonu aynı satırda bir kez çağırmamızı sağlardı. Halen de geçerli bir yoldur ancak Walrus Operatörü bir bakıma yazmamız gereken kod sayısını azaltıyor, bize daha temiz bir kod görünümü kazandırıyor. Bu yolu da sizinle paylaşayım.

f = lambda x: x ** 3
print(list(filter(lambda i: i < 30, [f(x) for x in range(10)])))

Burada filter isimli bir fonksiyon kullandık. f(x) fonksiyonu bir liste üretecinde şu şekilde kullanıldı: [f(x) for x in range(10)]. Her bir x sayısı için f(x) fonksiyonu çağrıldı. Bizim istediğimiz, küpü 30’dan küçük olan sayıları ekrana yazdırmaktı. Bu yüzden de filter fonksiyonunu kullandık. filter fonksiyonunun ilk argümanı bir fonksiyondur, ikinci argümanı ise bir dizidir. Basit bir şekilde şöyle kullanılır.

list(filter(lambda i: i % 2 == 0, range(10)))

Burada lambda fonksiyonu kafanızı karıştırmasın, def fonksiyonundan hiç bir farkı yok. Şöyle de yapabilirdik:

def f(x):
    """True veya False değerini döndüren bir fonksiyon"""
    return x % 2 == 0


list(filter(f, range(10)))

Bu yukarıdaki son iki kod örneğini size filter fonksiyonunu açıklamak için yazdım.

Aynı satırda f(x) fonksiyonunu iki kez yazmamak için iki farklı yöntem izleyebileceğimizi söyledim. Bunlardan birisi Walrus operatörünü kullanmak, bir diğeri ise f(x) fonksiyondan dönen değerlerin toplandığı listeyi filter fonksiyonu ile filtrelemek.

Umarım anlatabilmişimdir.

1 Like

Normalde bir degiskene deger atamak icin = kullaniyoruz. Orn:

x = 42

Bu sekilde yazdigimiz cumlenin (statement) kendisi bir degere sahip degil. Mesela:

y = (x = 42)

veya

if not (x = 42)

calismiyor cunku = de if/not da saginda deger tasiyan kodlar (expression) isteyen seyler.

:= operatoru atadigi degeri ayni zamanda donduruyor:

if (x := foo()) is not None:
    x.bar()
while (sayi_str := input("Sayi gir, cikis icin Q: ")) != 'Q':
    sayi = int(sayi_str)
    ...
2 Likes