Default Value

Rick Johnson rantingrickjohnson at gmail.com
Thu Jun 20 23:16:19 EDT 2013


On Thursday, June 20, 2013 7:57:28 PM UTC-5, Steven D'Aprano wrote:
> On Thu, 20 Jun 2013 11:05:32 -0700, Rick Johnson wrote:
> > Python functions are objects that take arguments, of
> > which (the arguments) are then converted to attributes
> > of the function object.
> Arguments in general are *not* converted to attributes. If
> you call a function func(x=1, y=2), arguments 1 and 2 are
> not stored as attributes anywhere. That would be silly,
> since 1 and 2 become local variables and there is no point
> in storing them for later use since they don't get used
> later. Only default values for parameters are stored for
> later use.

Obviously you've lost the ability to recognize sarcasm. :(

> They have to be stored *somewhere*, and Python chooses to
> store them as an attribute of the function object, where
> they can be easily inspected, rather than by storing them
> inside some undocumented and hidden location locked up in
> a binary blob.

I like how that last sentence implicitly argues against an
argument i never made, whilst explicitly supporting your
argument. But, by all means Steven, proceed.

> Even if Python chose late binding instead of early binding
> for function defaults, the default would *still* need to
> be stored somewhere.

No, if your passing in a symbol, then the object it points to
must exist *somewhere*. OTOH if your passing in a literal,
or an expression, then the subroutine will need to "store"
the resulting object. Yes.

> The only difference is that with early binding, the
> default value is calculated once, and the object stored,
> while with late binding the default value is re-calculated
> over and over again, every time it is needed, and a piece
> of code that calculates the default value is stored.

And that is *ONLY* the case using the currently broken
system. You're arguing that the status-quo is better
because the only alternative would be to re-evaluate the
argument every time, when in fact, i provided three code
examples that will not require re-evaluation of the mutable
and i did so without sacrificing readability. Your argument
is weak.

> > Ah-Ha! Urm, but wait! We already have a method to define
> > Objects. Heck, I can even create my own callable objects
> > if i want!
> >
> [snip]
> Yes, you can create callable objects by defining a
> __call__ method. That's okay. It is pure slander, invented
> by Perl programmers, that Python gives you "only one way
> to do it". Python has functions for 99% of your subroutine
> needs, and for more complex cases where your subroutine
> needs to store permanent data and make them available to
> the caller, you have class-based callables. But really,
> using a class-based callable is a PITA. You have to define
> a class, write an __init__ method, write a __call__
> method, instantiate the class, store the instance, and
> call it.

Mother of GOD call the authorities because a little girly
man has been violated! That mean old Rick and his insistence
on readability is causing a pandemic of carpal tunnel and
PTSD syndrome. Haul him away, lock him up, and throw away
the keys! Psst: That was sarcasm.

> > But then, i can even do it WITHOUT creating an object
> > definition:
> >   py> mutable = []
> >   py> def expandMutable(arg):
> >   ...     mutable.append(arg)
> >   ...
> [...]
> The biggest, most obvious problem with the expandMutable
> approach is that it relies on a global variable. I find it
> implausible that you, an experienced programmer, is
> unaware of the dangers of global variables.

I am quite aware of the dangers of globals, and i abhor
their use in 99 percent of the cases. But we're talking
about Python here *giggle*. The limits of a Python "global"
are the module for which it is declared. Plus, this is
quite amusing that you are now seemingly preferring the OOP
style; how many times have you made snide remarks about my
penchant for OOP? I dunno because i stopped counting after i
ran out of fingers! 

Yes i can only count to ten, there, i beat you to the joke.
Now we can focus again.

> > ANY of those approaches are much less confusing than the
> > current flaw
> Confusing for whom? Beginners, who don't know the first
> thing about Python?

Of course programming noobs are going to be confused by this.

> Programmers who are experienced with
> some other language but have no clue about what these
> weird __init__ and __call__ methods do?

So now your going to argue that experienced programmers are
going to intuit an IMPLICIT and unconventional subroutine
data persistence, but they cannot intuit EXPLICIT words like
"init" and "call"? Oh Please! 

> Programmers with
> 40 years experience who don't know anything about object-
> oriented code?

Even those old dogs who refuse to use GUI's and code in the
OOP style deserve a little more credit than you are giving
them Steven. They might be dinosaurs but they're not stupid.
Hardheaded, yes. Incapable of accepting change, yes. But
stupid, no no no.

> People who have been immersed in Python coding for 15 years?

Well, if they are confused after 15 years i would suggest
they take up a new profession.

> Every feature is confusing to *some* people and not others.

Indeed. But your not going win this argument by offering
such generic postulations. Yes, noobs will be completely
confused and experienced programmers from other languages
will suffer a "WTF" moment, quickly followed by a: "Now i
got to go RTFM because some cowboy designer decided to throw
me a curve ball!!!" moment.

When designing a language, intuitiveness should always be an
important consideration, however, it need not be the ONLY
consideration. There is no such thing an interface that will
be intuitive to *everyone* on planet earth.

But for this PyWart (and that's exactly what it is!) you're
not only dealing with a violation of intuitiveness, your
also dealing with a violation of fundamentals of subroutines;
which has been established for many years across many
languages.

> > and do not violate the least astonishment law.
> That's a misuse of the Principle of Least Astonishment.
> Not just a misuse, but in fact you've got it backwards:
> late binding of default variables would violate the
> principle of least astonishment. Python functions are
> created *once*, when defined. The cost of building the
> function -- compiling the source code to byte code,
> assembling the pieces into a function object, binding it
> to a name -- happens once and once only, not every time
> you call the function. So it is reasonable to expect that
> since the function is defined once, so are any default
> arguments.
>

Here you go again with this diversionary tactics! Of course
the function is only compiled once! Anything else would be
ludicrous. PAY ATTENTION! I'm not arguing that the damn
function should be compiled each time it's called, no, i am
arguing that each call to a subroutine should be a UNIQUE
TRANSACTION. That means that no state can be carried from
one transaction to another. 

> There are two obvious arguments against late binding: efficiency, and
> consistency. Late binding is less efficient: if the code that defines the
> default is expensive, you have to pay that cost once, that can't be
> avoiding. But late binding makes you pay it again and again and again:
> def f(arg, value=time.sleep(100)+5):  # simulate an expensive default
>     ...

You still don't understand what a TRANSACTION is do you? You
would rather beat subroutines with a hammer until they
resemble some pie in the sky, one size fits all
*monstrosity* instead of taking a few seconds out of your
precious time to creating a object to accomplish the same
task.

 BamBam Says: "BamBam make square peg fit through round hole"
 *BAM*
 *BAM*
 Mom Says: Okay BamBam. Let's play nice please.

> I have no doubt that if Python recalculated the default every time, you
> would be arguing that this is surprising and painful and that Python
> ought to calculate the value once and cache it somewhere.
> The other gotcha with late binding is that because the default is
> recalculated each time, it can surprise you by changing unexpectedly:
> def f(arg, value=x+5):
>     ...
> If the value of x changes, so does the value of the default. This may
> surprise you. (It would certainly surprise me.)

No Steven, because i wouldn't be foolish enough to write
code like that. That looks like a disaster waiting to happen!
But i must admit, i wish i could write bad code and then
justify it on the bases that a flaw in the language is going
to save me. Have you actually done this in reality? But more
importantly, do you realize that there exist better ways?

> > I'm quite Okay with Python functions being first class
> > objects, however, i am not okay with violating the
> > fundamental nature of subroutines,
> In what way to Python functions violate the fundamental
> nature of subroutines?

If you expect me to type it out twice then you're in for a
rude awaking. Next time, try reading my entire post.

> > especially when that violation can offer no clear and
> > arguable benefits and is in fact unreasonably esoteric
> > in nature.
> Early binding offers clear benefits:
> - consistency: the default cannot mysteriously change value due
>   to an unrelated change;

That's a solution to a problem only a fool would create.

> - efficiency: the default is calculated once, not over and over;

I prefer clear and readable code over obfuscation and magic.
If i want to be astonished, i'll go watch David Copperfeild
disappear an elephant, thank you very much.



More information about the Python-list mailing list