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. -- http://mail.python.org/mailman/listinfo/python-list