"x += y" ile "x = x + y" arasında ne zaman fark olur?
Hep duyarız, x += y
ifadesi ile x = x + y
ifadesi denktir diye. Fakat her zaman değil! Python kodlarken bilmemiz gerekenler var. Alttaki koda bakalım:
import numpy as np y = np.linspace(0, 1, 10) x = np.repeat([1], 10) x += y print x # Çıktı: [1 1 1 1 1 1 1 1 1 2] x = np.repeat([1], 10) x = x + y print x # Çıktı: [ 1. 1.11111111 1.22222222 1.33333333 1.44444444 1.55555556 # 1.66666667 1.77777778 1.88888889 2. ]
Sonuçlar farklı çıkıyor. Peki, neden? İpucu kullanılan verilerin tiplerinde yatıyor.
x = np.repeat([1], 10) print x.dtype # Çıktı: int32 y = np.linspace(0, 1, 10) print y.dtype # Çıktı: float64 x += y print x.dtype # Çıktı: int32 x = x + y print x.dtype # Çıktı: float64
Demek ki x += y
ifadesi tam olarak x = x + y
gibi çalışmıyor. İlkinde, işlem sonucunda elde edilecek veri tipi atanacak verinin tipiyle aynı oluyor. Yani int32
. Fakat x = x + y
ifadesi için önce toplam hesaplanıyor ve toplamın sonucunda elde edilen veri tipi baskın çıkıyor. float64
ile int32
tiplerinin toplamı tabii ki float64
baskınlığıyla sonuçlanıyor.
Daha teknik ifade edecek olursak ilk ifade __iadd__
metodunu, ikincisi ise __add__
metodunu çağırıyor. API perspektifinden bakarsak __iadd__
değişebilir (mutable) nesnelerin yerinde (in-place) değişmesi için kullanmak üzere sunulmuştur. __add__
metodu ise yeni bir örnek döndürür. Değişemez (immutable) nesneler içinse her ikisi de yeni örnekler döndürür, farkları dönen örneklerin isimuzayları (namespace) olacaktır. __iadd__
yeni nesneyi özgün nesnenin isimzayına atar.
Başka bir örneğe bakalım:
a = [1, 2, 3] b = a b += [1, 2, 3] print a # Çıktı: [1, 2, 3, 1, 2, 3] print b # Çıktı: [1, 2, 3, 1, 2, 3]
ve şununla kıyaslayalım:
a = [1, 2, 3] b = a b = b + [1, 2, 3] print a # Çıktı: [1, 2, 3] print b # Çıktı: [1, 2, 3, 1, 2, 3]
Fark etmelisiniz ki ilk örnekte a
ve b
aynı nesneyi işaret ediyorlar ve sonuç ikisine de yansıyor. Fakat ikinci örnekte b
yeni bir nesneye atanıyor, yani işaret ettiği nesne farklılaşıyor ve a
bu değişiklikten etkilenmiyor.
Aslında __iadd__
için şuna bakılıyor:
try: i = i.__iadd__(1) except AttributeError: i = i.__add__(1)
Dolayısıyla sizin yazacağınız sınıflarda __iadd__
metodunu ayrıca kodlamadıysanız aralarında bir fark olmayacaktır.