4 ms·
Is this a designed feature or something that just happened? I really think that this behaviour is erroneous and unexpected. With python (and many other languag
by Johnny_Brahms 10y ago
Is this a designed feature or something that just happened? I really think that this behaviour is erroneous and unexpected.
With python (and many other languages) I find myself getting bitten by behaviour like this every now and then. I use scheme for almost all my personal projects, and I can only remember getting bitten twice. Once was unexpected, and the other was laziness on my part.
- lalaithion 10y agoBasically it just boils down to reference vs value. Both of the errors in this code occur because python uses a reference instead of a value – I agree that they can be annoying and somewhat unexpected, but they make sense once you realize what's behind them. In the method=[] part, the error occurs because python creates a single list, and passes that list by reference (as all lists are passed) into the function. In the lambda part, the error occurs because python captures the variable from the enclosing scope by reference, not by value (as normal functions do with globals).
- Johnny_Brahms 10y agoI understand how it is sort of a detail of how python works. But I also can't understand why someone thought "hmm. this is rather unexpected. Let's keep it that way". It would be trivial to have python re-create an empty list. Or is this pattern actually used? It seems rather perl5-y.
- detaro 10y agoFor empty lists it would be trivial, yes, but for arbitrary objects it wouldn't be. And only the empty list behaving different would be weird.
- Matthias247 10y agoI understand the "capturing i in a closure by reference" part, since that error is also common in other languages which capture variables by reference, and don't create a new reference per loop iteration. However the default parameter issue looks like a python specific issue which is really strangely designed. I would normally say [] is a literal for an empty list which creates a new instance of an empty list every time it's used. So when it's used as a default parameter a fresh empty list should be created all times. Is [] is global reference to a single mutable list which is only initially empty? That would make it pretty useless, since everyone could mutate it. If it's a single reference then that should at least be an immutable list which throws some exception when someone messes around with it.
- zaptheimpaler 10y ago>Is [] is global reference to a single mutable list which is only initially empty? No, the problem is default arguments to methods are evaluated once, when the method is created and that value is used for all calls. I don't know why that is, its definitely strange - any other language would evaluate the default args each time a function is called just like the regular args.
- jVint 10y agoThen you would have the problem that something like mydefault=3, def f(default=mydefault):... would change it's evaluation if anyone ever defined mydefault=4. That would leave users unable to define any variable thats ever mentioned in default values of any function in any library they are using without causing very unexpected behaviors. What languages are you thinking of where default values set to a references are set to a copy of that reference as it was at definition time at every evaluation?
- zaptheimpaler 10y agoNot sure if i completely understand, but the example you mentioned would work in Scala. If a mutable variable is referenced in default args, its value at define-time is used. Example: scala> var x = 5 x: Int = 5 scala> def func(arg1: Int = (x+1)) = { println(arg1)} func: (arg1: Int)Unit scala> func() 6 scala> var x = 7 x: Int = 7 scala> func() 6 //unchanged For reference vars the closure captures a local copy: scala> var list = List(1,2,3) list: List[Int] = List(1, 2, 3) scala> def printList(arg1: List[Int] = lis) = { println(arg1) } printList: (arg1: List[Int])Unit scala> printList() List(1, 2, 3) scala> var list = List(4,5,6) list: List[Int] = List(4, 5, 6) scala> printList() List(1, 2, 3)