On 19/11/2015 16:01, Steven D'Aprano wrote:
On Fri, 20 Nov 2015 12:19 am, BartC wrote:

You know, for somebody who claims to design and implement your own
languages, you sometimes go to a remarkable effort to claim to be a dummy.
You write your own interpreter, but can't understand early versus late
binding? I don't think so.

No I don't; so? Maybe my interpreter can do its thing without being aware that what it's doing has been called 'late binding' or 'early binding' by someone else.

At least its default values work as expected! (And they can also be applied to existing external functions. Even C API functions where the implementation doesn't support these features.

So if an argument is missing, it applies the default I specify in its place. It's that simple.)

I understand that the simplest things can be perplexing if you look at them
the wrong way. But we've explained multiply times now, or at least tried to
explain, that the argument default is a single object. That is blindingly
obvious once you look at it the right way, and it is a nice, clean design.

I can understand now how it works as it does. But I still think it is unintuitive. A language design could have chosen to make it work however it liked.

There's no need to introduce extra modes where code has to be stored away
to be evaluated later (apart from the body of the function itself).
Everything works the same way: assignment always evaluates a result and
binds it to the name, whether that assignment is in a parameter list or
not.

If you insist on thinking about it in terms of how C or Pascal work, of
course you will confuse yourself. The argument default is evaluated when
the function is created, and the resulting object is stored away for later
use, inside the function. That is clean and easy to understand.

I'm not saying that the behaviour with mutable defaults

The whole concept of 'mutable' default is alien to me. A default is just a convenient device to avoid having to write:

  fn(0) or fn("") or fn([])

You just write fn() instead. But it shouldn't come at the cost of completely different semantics! Because then it can't really be called a default value at all.

 isn't surprising to
somebody coming from a completely different paradigm. I was surprised by it
too, the first time I got bitten.

So you didn't bother reading the LRM either!

py> def demo_const(x, y=[]):
...     return x + len(y)

Exactly as you should expect. Where you run into trouble is when the default
value is NOT a constant:

py> def demo_variable(x, y=[]):
...     y.append(1)
...     return x + len(y)

Sorry, what is the default value in each of these? As the first lines of the defintions look identical apart from the function names.

...
py> demo_variable(5)
6
py> demo_variable(5)
7
py> demo_variable(5)
8


If you modify the value, the value will be modified. Why are you surprised
by this?

Which value is being modified? The []?

And most often that constant is 0, "" or an empty list.

You want these very common examples to /just work/ instead of going to
lengths trying to explain why they don't.

Ah, the good-old "I shouldn't have to think to understand programming" model
of programming. Because that works so well.

It works well when sharing code because not everyone understands things at the same level.

Maybe you can wrap the entire module inside a function? Other than a bit
at the end that calls that function. Does that solve the global lookup
problem?

No.

Why not?


When you deal with mutable objects, you have to expect them to mutate.
The whole point of mutability is that their value can change.

That [] doesn't look like an object that could change.

Of course it does.

You've lost me know.

Are you saying that:

  a=[]

why sometimes not assign an empty list, because that [] could have been modified?

It is a list literal, like int literals, float literals,
string literals and the rest.

Another surprise? Literals by definition can't change:

def fn():
        a=[10,20,30]
        a.append(999)

I would hope that a is set to [10,20,30] at each entry to the function!

You presumably think differently because you have some inside knowledge
of how Python works, and know that that [] undergoes a one-time
assignment to a local, persistent 'default' variable where it's value
can indeed by changed. (Thanks to another Python feature where an
assignment is a very shallow copy of an object.) And it is that volatile
variable that is the actual default.

Assignments are not copies at all.

if you write A=B then something of B needs to have been copied into A, even if it's just the reference that B contains. Otherwise it would be difficult to get A to refer to the same object as B.

--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to