Python'un Denizayı Operatörü Nedir
Atama ifadesi, := operatörünü kullanır ve daha yaygın olan atama deyimine (= operatörünü kullanır) benzer görünür. Ancak ikisi arasında önemli bir fark vardır.
Bir deyim, bir eylem gerçekleştiren kod birimidir. Bir ifade ise bir değere değerlendirilebilen bir deyimdir. Dolayısıyla bir ifade bir değer döndürürken, ifade olmayan deyimler herhangi bir değer döndürmez.
Python'un REPL'i (Read, Evaluate, Print, Loop) bir ifade değerlendirildiği anda değerini gösterir. Ancak ifade olmayan bir deyim yürütüldüğünde herhangi bir değer gösterilmez:
>>> import random # Not an expression
>>> 10 * 2 # An expression
20
import deyimi herhangi bir değere değerlendirilmez. Oysa 10 * 2, bir değere değerlendirilen bir ifadedir.
= operatörünü kullanan atama deyimi, bir nesneyi bir değişkene veya başka bir başvuruya atar, ancak değeri döndürmez. Atama ifadesi, yani denizayı operatörü, atama deyimiyle aynı işlemi yapar ama ayrıca nesneyi de döndürür:
>>> value = 10 # Assignment statement
>>> value
10
>>> (value := 20) # Assignment expression
20
Atama deyiminin, atama ifadesinin aksine değeri döndürmediğine dikkat edin. Bu nedenle, bir atama ifadesi birkaç işlemi birleştirir:
:=operatörünün sağ tarafındaki ifadeyi değerlendirir.- Bu değeri bir değişken adına atar.
- Değeri döndürür.
Belirsizliği azaltmak için, bu örnekte olduğu gibi, atama deyimi yerine atama ifadesi kullanıldığında parantezler zorunlu söz dizimidir. Denizayı operatörünün söz dizimi gereksinimleri hakkında daha fazlası bu eğitimde ileride yer alıyor.
Bir atama ifadesi, Python'da ifadelerin kullanılabildiği her yerde kullanılabilir. Bir örneğe bakalım:
print(f"The number is {(value := 50)}")
print(value)
The number is 50
50
value değişken adı ilk satırdaki f-string içinde tanımlanır. Ancak tamsayı aynı zamanda doğrudan f-string içindeki süslü parantezlere de döndürülür. f-string'lerdeki süslü parantezler mutlaka bir ifade içermelidir; bu da atama deyiminin neden kullanılamadığını açıklar.
Python’un Denizayı Operatörü için Kullanım Senaryoları
Denizayı operatörü için iki yaygın kullanım senaryosu, kodu sadeleştirmek ve optimize etmektir.
Kodu sadeleştirme
Denizayı operatörünün yaygın bir kullanım alanı, bazı koşullu ifadelerde olduğu gibi, normalde bir değişkenin kullanılmadan önce tanımlanması gereken yerlerde kodu sadeleştirmektir. Aşağıdaki while döngüsünü düşünün:
import random
value = random.randint(1, 20)
while value < 18:
print(value)
value = random.randint(1, 20)
7
5
1
11
12
1
9
Bu kod, üretilen rastgele değer 18'den küçük olduğu sürece while bloğunu çalıştırır. value değişkeninin, while deyiminde kullanılabilmesi için döngüden önce tanımlanması gerekir. while bloğunun sonunda value'ya yeni bir rastgele sayı atanır.
:= atama ifadesi, kod satırlarını azaltmak ve programda random.randint() çağrısını tek bir yerde yapmak için kullanılabilir:
import random
while (value := random.randint(1, 20)) < 18:
print(value)
1
9
2
4
9
15
11
Her yeni yinelemede while döngüsü başladığında value'ya yeni bir rastgele sayı atanır.
Kodu optimize etme
Şimdi liste üreteçlerini kullanan başka bir örneğe bakalım. Aşağıdaki kodu düşünün: Tarihler içeren bir dizi dizeyi filtreler ve yalnızca belirli bir yıl içindeki tarihleri içeren datetime.datetime nesneleri listesini oluşturur:
from datetime import datetime
def format_date(date_str):
return datetime.strptime(date_str, "%Y-%m-%d")
dates = ["2024-01-01", "2022-12-31", "2024-06-15", "2023-08-23", "2024-11-30"]
formatted_dates = [
format_date(date)
for date in dates
if format_date(date).year == 2024
]
print(formatted_dates)
[datetime.datetime(2024, 1, 1, 0, 0), datetime.datetime(2024, 6, 15, 0, 0), datetime.datetime(2024, 11, 30, 0, 0)]
format_date() işlevi, yyyy-mm-dd biçiminde bir tarih içeren bir dize alır ve bir datetime.datetime nesnesi döndürür. datetime.datetime nesnesi özniteliklerinden biri, tarihin yıl bileşenini içeren .year'dır.
Son listede yalnızca 2024'e ait üç tarih yer alır ve öğeler artık dizeler yerine datetime.datetime nesneleridir. Liste üreteci, if yan tümcesinde format_date()'i çağırır. Ancak format_date(), liste üretecinde listeye eklenecek değerleri üreten ilk ifadede de çağrılır. Aynı işlevin aynı argümanla iki kez çağrılması verimsizdir; özellikle de işlev programın performansında dar boğazsa.
Aynı işlevi iki kez çağırmaktan kaçınmanın bir yolu, işlevi çağırıp kullanmadan önce bir değişkene atamaktır. Ancak bu, liste üreteci kullanmaya devam ederken atama deyimiyle yapılamaz. Bu çözüm standart bir for döngüsü gerektirir:
from datetime import datetime
def format_date(date_str):
return datetime.strptime(date_str, "%Y-%m-%d")
dates = ["2024-01-01", "2022-12-31", "2024-06-15", "2023-08-23", "2024-11-30"]
formatted_dates = []
for date in dates:
formatted_date = format_date(date)
if formatted_date.year == 2024:
formatted_dates.append(formatted_date)
print(formatted_dates)
[datetime.datetime(2024, 1, 1, 0, 0), datetime.datetime(2024, 6, 15, 0, 0), datetime.datetime(2024, 11, 30, 0, 0)]
Denizayı operatörü, liste üreteciyle uyumlu alternatif bir yol sunar; çünkü işlevin döndürdüğü biçimlendirilmiş tarih aynı ifadede hem bir değişken adına atanabilir hem de döndürülebilir:
from datetime import datetime
def format_date(date_str):
return datetime.strptime(date_str, "%Y-%m-%d")
dates = ["2024-01-01", "2022-12-31", "2024-06-15", "2023-08-23", "2024-11-30"]
formatted_dates = [
formatted_date
for date in dates
if (formatted_date := format_date(date)).year == 2024
]
print(formatted_dates)
[datetime.datetime(2024, 1, 1, 0, 0), datetime.datetime(2024, 6, 15, 0, 0), datetime.datetime(2024, 11, 30, 0, 0)]
Liste üretecindeki atama ifadesi, parantez içine alınmış (formatted_date := format_date(date)) ifadesidir. Bu ifade format_date() işlevini çağırır, değerini formatted_date değişkenine atar ve değeri döndürür. Atama ifadesi bir datetime.datetime nesnesine değerlendirildiğinden, kod .year özniteliğine erişir ve eşitlik operatörüyle 2024 ile karşılaştırır.
Liste üretecinde if yan tümcesi, listeye kaydedilecek değeri üreten ifadeden önce yürütülür. Bu nedenle denizayı operatörü if yan tümcesinde kullanılır ve bu atama ifadesinde tanımlanan değişken, liste üretecinin ilk ifadesi olarak kullanılır.
Python’un Denizayı Operatörü Üzerine Tartışmalar
Atama ifadesi tüm Python programcıları tarafından sevilmiyor. Bazıları kodu sadeleştirmenin bir yolu olarak görürken, diğerleri kodu daha az okunur hâle getirdiğini düşünüyor ve daha uzun seçenekleri tercih ediyor. Okunabilirlik öznel olabilir; bu yüzden denizayı operatörünün kodu daha mı az mı okunur kıldığı konusunda görüşler farklılık gösterir.
Önceki bölümdeki son örnek, gerekli ödünleri gösteriyor. Denizayı operatörü olmadan bu örnekteki kodun önce boş bir listeyi başlatması, ardından bir for döngüsünde değerlere ekleme yapması gerekir. Bu çözüm, bu iş için optimize edilmiş liste üreteçlerini kullanmaktan daha uzun ve daha az verimlidir.
Bununla birlikte, standart for döngüsü çözümü, özellikle performansın öncelik olmadığı durumlarda, denizayı operatörünü kullanmak yerine daha fazla kod yazmayı tercih eden bazı programcılar için daha okunabilir olabilir.
Birçok kodlama stil rehberi hâlâ atama ifadesinden kaçınılmasını ya da yalnızca sınırlı şekilde kullanılmasını öneriyor.
Python’un Denizayı Operatörü: Söz Dizimi Kuralları
Söz dizimi kuralları nedeniyle denizayı operatörünü ilk keşfederken söz dizimi hatalarıyla karşılaşmanız olağandır.
Atama deyimi = ile atama ifadesi := arasında karışıklığı önlemek için, her iki seçeneğin de söz dizimsel olarak geçerli olduğu bir durum yoktur. Bu nedenle, çoğu zaman atama ifadesini parantez içine almak gerekir:
(value := 20) # Valid
value := 20 # Invalid (SyntaxError)
Bu durumda atama ifadesinin parantez içine alınması gerekliliği, parantez içine alınamayan atama deyiminin gerekliliğinin tersidir.
Ancak, atama ifadesi her zaman parantez gerektirmez:
import random
if value := random.randint(0, 3):
print(f"{value} is greater than 0")
1 is greater than 0
if deyimindeki atama ifadesi 0 ile 3 arasında rastgele bir sayı üretir ve bunu value değişkenine atar. 1, 2 ve 3 truthy değerlerdir ve bu değerler üretildiğinde if bloğundaki kod çalışır. Ancak random.randint() 0 döndürdüğünde, bu değer falsy olduğundan, if bloğu yürütülmez.
if anahtar sözcüğünden sonra atama deyimi geçerli değildir. Dolayısıyla bu durumda bir karışıklık yoktur ve parantez gerekmez.
Bu örnek, atama ifadesi hakkında bir diğer önemli noktayı da gösterir. Atanan değişkenin kapsamı normal LEGB kurallarını izler. Bu nedenle bu örnekte value değişkeni genel kapsamın her yerinde kullanılabilir:
import random
if value := random.randint(0, 3):
print(f"{value} is greater than 0")
print(value)
2 is greater than 0
2
Bir atama ifadesi bir işlev tanımı içinde kullanılırsa, değişken yalnızca işlevin yerelinde mevcut olacaktır. Bu davranış, atama deyimiyle oluşturulan değişkenlerle aynıdır.
Bu örnek, denizayı operatörü kullanılırken başka bir olası tuzağı göstermek için değiştirilebilir. if deyimine bir karşılaştırma operatörü ekleyelim:
import random
if value := random.randint(0, 3) < 2:
print(f"{value} is less than 2")
True is less than 2
Çıktıdaki gösterim bu koddaki soruna işaret eder; çünkü value bir tamsayı yerine Boole True'dur. Denizayı operatörü, tüm operatörler arasında en düşük önceliğe sahiptir ve yalnızca virgül daha düşük önceliklidir. Bu nedenle, küçüktür operatörü < önce değerlendirilir ve çıktısı value'ya atanır. Bu durumu ele almak için parantez gerekir:
import random
if (value := random.randint(0, 3)) < 2:
print(f"{value} is less than 2")
0 is less than 2
Parantezler en yüksek önceliğe sahip olduğundan, artık önce atama ifadesi değerlendirilir. random.randint()'in döndürdüğü sayı value'ya atanır ve küçüktür operatörünün ilk işleneni olarak kullanılır.
Atama deyiminin aksine, denizayı operatörü yalnızca değişken adlarına değer atayabilir; aboneliklere veya özniteliklere değer atamak için kullanılamaz:
(name := "James") # Valid
points = {"James": 10, "Mary": 20}
(points["Sarah"] := 30) # Invalid
class Article:
pass
article = Article()
(article.title := "The Walrus Operator") # Invalid
Denizayı operatörüyle bir abonelik kullanarak ya da bir özniteliğe değer atamak mümkün değildir.
Sonuç
:= söz dizimini kullanan ve sıklıkla denizayı operatörü olarak anılan atama ifadesi, Python'a nispeten yeni eklenmiştir. = operatörünü kullanan atama deyimi ise bir değişken adına değer atamanın daha yaygın yoludur.
Bununla birlikte, denizayı operatörü bu atama işlemini, atanan değeri de döndürerek genişletir; bu da bu atamayı bir ifade yapar. Dolayısıyla, atama ifadesini Python'da diğer ifadeleri kullanabildiğiniz her yerde kullanabilirsiniz.
Yine de Python topluluğu denizayı operatörünün faydası ve okunabilirliği konusunda ikiye bölünmüş durumda. Bu nedenle atama ifadesi, Python'a yeni eklenen diğer özellikler kadar sık kullanılmıyor. Bu operatörü nasıl kullanacağınızı bilmek harika, ama aşırıya kaçmayın!
Malta Üniversitesi’nde lisans düzeyinde Fizik ve Matematik okudum. Ardından Londra’ya taşındım ve Imperial College’da Fizik alanında doktoramı tamamladım. İnsan retinasını görüntülemek için yeni optik teknikler üzerine çalıştım. Şimdi Python hakkında yazmaya, Python’u anlatmaya ve Python öğretmeye odaklanıyorum.


Python 3.8, dile yeni bir operatör ekledi. Resmî adı atama ifadesi ve
:=operatörünü kullanır.Ancak yaygın olarak denizayı (walrus) operatörü olarak anılır; çünkü bir denizayının dişlerine benzer!
Bu operatör dile eklendiğinde, genellikle sakin olan Python dünyasında tartışmalara yol açtı ve kullanımı hâlâ nispeten sınırlı. Yine de atama ifadesi artık Python'un bir parçası ve bazı durumlarda faydalı olabilir.
Bu eğitimde Python'un denizayı operatörünün nasıl çalıştığını inceleyecek ve hangi durumlarda kullanılabileceğini tartışacağız.