Python ile yeterince uzun süre uğraşan herkes aşağıdaki sorunla ısırıldı (veya parçalara ayrıldı):
def foo(a=[]):
a.append(5)
return a
Python acemi bu işlev her zaman yalnızca bir eleman içeren bir liste dönmek için beklenir: [5]
. Sonuç bunun yerine çok farklı ve çok şaşırtıcı (bir acemi için):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
Bir müdürüm bir zamanlar bu özellikle ilk karşılaşmasını yaptı ve ona dilin "dramatik bir tasarım hatası" adını verdi. Davranışın altında yatan bir açıklama olduğunu ve iç kısımları anlamadığınızda gerçekten çok şaşırtıcı ve beklenmedik olduğunu yanıtladı. Ancak, aşağıdaki soruya (kendi kendime) cevap veremedim: varsayılan bağımsız değişkeni işlev tanımında değil, işlev yürütmesinde bağlama nedeniniz nedir? Deneyimli davranışın pratik bir kullanımı olduğundan şüpheleniyorum (C'de üreme hataları olmadan gerçekten statik değişkenleri kullanan?)
Düzenle :
Baczek ilginç bir örnek verdi. Yorumlarınızın ve özellikle Utaal'ların çoğuyla birlikte daha ayrıntılı bir şekilde açıkladım:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
Bana göre, tasarım kararının parametrelerin kapsamını nereye koyacağı göreceli gibi görünüyor: işlevin içinde mi, yoksa "birlikte" mi?
İşlevin içindeki x
bağlantının yapılması, işlev tanımlanmadığında, derin bir kusur gösterecek bir şey olduğunda belirtilen varsayılan değere etkin bir şekilde bağlı olduğu anlamına gelir : def
çizgi, bağlamanın ( işlev nesnesi) tanımda ve bölüm (varsayılan parametrelerin atanması) işlev çağırma zamanında olur.
Gerçek davranış daha tutarlıdır: bu satır yürütüldüğünde her satır, yani işlev tanımında değerlendirilir.
[5]
" Ben bir Python acemi değilim ve ben bunu beklemezdim, çünkü belli ki foo([1])
dönecektir [1, 5]
, değil [5]
. Söylemek istediğiniz şey, bir aceminin parametresiz olarak adlandırılan işlevin her zaman geri döneceğini beklemesi [5]
.