![](https://secure.gravatar.com/avatar/5615a372d9866f203a22b2c437527bbb.jpg?s=120&d=mm&r=g)
On Tue, May 26, 2020 at 02:25:38AM +0300, Paul Sokolovsky wrote:
I'd suggest that people should love "explicit is better than implicit" principle of the language.
Explicit meaning that you need to use a specific symbol that means "this is to be late-bound"?
No, it means "use explicit 'if' if you want to deal with mutable default".
Point of terminology here. Let's not conflate two separate issues. There is nothing wrong with putting a mutable default value directly in the function signature def func(param=[]): works absolutely fine for what it does. It's just that what it does is not what some people want it to do. The real issue is not mutable defaults as such, but early versus late binding.
Or explicit meaning "something that I like", as opposed to implicit meaning "something that I don't like", which is how most people seem to interpret that line of the Zen?
I'd prefer to think in terms of implementation complexity. Implemented in adhoc way (and that's how things get implemented in C, in particular, in CPython), it will be quite a noticeable complexity up-glitch to function representation/implementation, and all it achieves is trading one confusion for another.
(Well, for two others: why the heck there're 2 ways to define default args, which is to use when, and why one of them doesn't work across subexpression refactoring.
To answer those questions: (1) There are two ways to define default args, because there *are* two ways to define default args: - calcuate the default argument once and re-use it as needed; - or re-calculate the default argument each time you need it. Asking why there are two ways is a very odd question. It's rather like asking why there are two ways to travel around a circle (clockwise and counter-clockerwise, and at least three ways to parse a binary tree (preorder, inorder, postorder). Because there just are, that's the nature of the thing. (2) You use whichever one you need for the specific function you are writing. Nobody can answer that except yourself. If you don't understand Python's object model well enough to answer that question, then you're going to be stumbling over problems in all sorts of things: a = [] b = a b.append(1) a == [1] # Why??? If you want the default value to be X, then: - if you want a fresh X each time, then you want late binding; - if you want the same X each time, then you want early binding; - if you don't care, then early binding is likely to be a little more efficient. (3) One of them doesn't work across subexpression refactoring for the exact same reason that it doesn't work in other function calls, and for the same reason it may not work *right now* with the `if arg is None` idiom: def func(arg=None): if arg is None: arg = print('computation') or [] versus: c = print('computation') or [] def func(arg=None): if arg is None: arg = c Likewise if you refactor an expression outside of a loop, the behaviour will change.
Oh, and old confusion still stays with us.
*shrug* People who code on automatic pilot without thinking about what the code they write *actually* means rather than what they *assume* it means are always going to be confused by one thing or another. I only have so much sympathy for people who get confused or angry when the language doesn't read their mind and Do What I Mean. At some hypothetical future point that Python has some syntactic method for explicitly marking defaults as late-binding: # straw-man proposal def func(s='', arg=mutable {}): if people continue to write `arg={}` when they want `arg=mutable {}` then I will have no sympathy for them. That's just a PEBCAK error, not a language flaw.
There's really no easy way to resolve the original confusion, short of banging mutable defaults.
How does the compiler know if an arbitrary object is mutable or not? When I want early binding of a mutable object, and I sometimes do, why should the compiler tell me I can't have it just because some other person may, or may not, be confused by the semantics of the language? -- Steven