Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Default Value

Reply
Thread Tools

Default Value

 
 
Chris Angelico
Guest
Posts: n/a
 
      06-21-2013
On Fri, Jun 21, 2013 at 1:16 PM, Rick Johnson
<(E-Mail Removed)> wrote:
> On Thursday, June 20, 2013 7:57:28 PM UTC-5, Steven D'Aprano wrote:
>> 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.


Why should that be? Why is a subroutine not allowed to retain any state?

You're free to write code in a purely functional style if you like -
all objects must be immutable, all functions must have no side effects
and simply return a value. That's not the only way to code, and it is
*definitely* not a rule to be codified into Python. One of Python's
strengths is that it permits many styles of programming, without
shoehorning every programmer and every task into one model.

Of course, RickPy 4000 is welcome to enforce all these sorts of inane
rules if it likes. I shan't be using it if it does.

ChrisA
 
Reply With Quote
 
 
 
 
Rick Johnson
Guest
Posts: n/a
 
      06-21-2013
On Friday, June 21, 2013 2:10:49 AM UTC-5, Chris Angelico wrote:
> Why should that be? Why is a subroutine not allowed to
> retain any state?


I refuse to repeat myself for lazy readers!

> You're free to write code in a purely functional style if
> you like


I don't want to write code in a purely functional style, i
find that style too restricting.

> all objects must be immutable,


That would suck!

> all functions must have no side effects and simply return
> a value.


No thanks!

> One of Python's strengths is that it permits many styles
> of programming, without shoehorning every programmer and
> every task into one model.


Yes, and i consider that aspect of Python a virtue. But this
"persistence of mutable arguments" is not a virtue, it's an
abomination!

 
Reply With Quote
 
 
 
 
Rick Johnson
Guest
Posts: n/a
 
      06-21-2013
On Thursday, June 20, 2013 5:28:06 PM UTC-5, Lefavor, Matthew (GSFC-582.0)[MICROTEL LLC] wrote:
>
> [snip example showing dummy coder doing something dumb]
>
> +1. This is what convinces me that keeping references to
> keyword arguments is actually the right thing to do.
>
> Perhaps I'm biased because I'm used to the mutable-
> argument behavior by now, but the gotcha described above
> seems to be much harder to track down and understand than
> any bugs caused by mutable arguments. With mutable
> arguments, at least you know the cause is in the function
> definition. If you initialized variables each time, you'd
> have to track the problem down across the entire
> namespace.


That's because you and many other folks, who keep supporting
this BS idea, have become SO accustomed to writing code in a
sloppy manner, that you need this flaw to save yourself,
FROM YOURSELF!

" Hello, allow myself to introduce myself"

Apparently you don't understand the value of writing rock
solid code. Instead of passing your mutables in as
arguments, all you have to do is reference them properly in
the BODY of the subroutine and everything will work just
fine. If you fear global level variables then write up a
simple Object definition to encapsulate the mutable and make
it callable.

================================================== ==========
Thought Exercise:
================================================== ==========

Let's imagine for a second if Python allowed mutable keys in
a dictionary, would you be surprised if you used a mutable
for a key, then you mutated the mutable key, then you could
not access the value from the original key?

## Imaginary code ##
py> lst = [3]
py> d = {1:2, lst:4}
py> lst.append(10)
py> d[lst]
opps, KeyError!

Would you REALLY be so surprised? I would not. But more
importantly, does Python need to protect you from being such
an idiot? I don't think so!

Any "intelligent" programmer would NEVER use mutable keys
for a hash table -- unless he had a very good reason and was
willing to take the risks -- EVEN IF the language allowed
such foolishness!

But you people will sit here all day arguing that "early
binding" is warranted on the grounds that people need to be
protected from doing stupid things -- like passing mutables
as arguments to subroutines. This is a weak argument. Tell
me you have something better, tell me the fate of this
language does not revolve around benevolent idiocy!

If you really want to save the poor idiot from writing code
that could fail, a leader ruled by benevolence, but who has
a modicum of intelligence remaining, would simply throw up a
warning.

Warning:
Argument "lst" to function "poopoo" has been mutated,
which could cause a subtle bug on successive calls.
YOU HAVE BEEN WARNED!

What you never, EVER, want to do is to use idiots for an
excuse to create some esoteric abomination of persistent
mutables between successive calls of subroutines.

> I, for one, would much rather follow the rule "don't use
> mutable arguments in function definitions"


Yes, that's the exact point i'm making! A little self
discipline can go a long way

> than "don't ever re-use the name of your variables."


Well, we're not even talking about that, but i understand
the value of your statement. Although, i think your
comparing Apples and Oranges.

PS: First you support the opposition. now you go an do a
180? You're confusing the hell out of me Matthew! @_@
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      06-21-2013
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.
> 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!
>
> Observe:
> py> class FuncAdd(object):
> ... def __init__(self, ivalue):
> ... self.ivalue = ivalue


Notice how you are storing state here? I thought you said, and I quote:

"When the subroutine is completed, ALL INPUTS and local variables are
expected to be destroyed. If the programmer wants a return value, he need
simply ask. Data persistence is NOT a function of subroutines!"
[emphasis added]

And yet here you are defining persistent input ("ivalue") to the callable
subroutine, which is stored as external state and not destroyed at the
end of the subroutine call:

> ... def __call__(self, numeric):
> ... return self.ivalue + numeric
> ...


All you have done here is define a subroutine with state, precisely the
thing that you say subroutines must never have. What you haven't done is
define a function which takes a default value that can be overridden when
called. Your argument is invalid.



--
Steven
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      06-21-2013
On Thu, 20 Jun 2013 20:16:19 -0700, Rick Johnson wrote:

> 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:


>> They [default argument values] 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.


You're overly defensive. I never said, or even suggested, that you argued
the opposite. I simply state a fact: any language with default arguments
must store the default argument somewhere. In a language with early
binding of default arguments, the *value itself* must be stored. In a
language with late binding, *the expression that generates that value*
(sometimes called a "thunk") must be stored.

The consequence of this fact is that if you wish to argue that functions
have no business storing state, then you're arguing that functions must
not have default arguments.


[...]
>> 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.


Passing in a symbol? I'm afraid I don't understand you. Do you mean a
name? Something like:

def func(x=y):
...

A single name, like 'y' above, is an expression. In any case, while the
name must exist at the time the function is defined, it does not need to
exist when the function is called:

py> y = 23
py> def func(x=y):
.... return x
....
py> del y
py> func()
23


>> 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.


No. You have failed to understand. ANY language that offers default
values for function parameters must operate under the same limitation.
The language must store either the default value itself, or some
executable expression that generates that default value.

Even if your language doesn't offer default values, all this means is
that the responsibility for doing this is moved away from the compiler to
you. For instance, if your languages offers an "is_undefined" function,
you can manually store the default value in a global variable and then
retrieve it when needed:


# Store function state in a global variable.
default := [];

def func(x):
if is_undefined(x):
{
x := default;
}
...


That suffers the *exact same gotcha* as Python if the default value is
mutable.

Or you can store the state in a callable class, what C++ calls a functor:

class MyClass:
# Store function state in a class member.
default := [];
def __call__(this, x):
if is_undefined(x):
{
x := this.default;
}
...

This too suffers the *exact same gotcha* as Python if the default is
mutable. Storing the function state as an instance member instead of a
class member doesn't save you; the same applies.

There are only three ways to avoid the mutable default gotcha:

* Prohibit default arguments, and don't provide an is_undefined
test. All function arguments *must* be supplied explicitly by
the caller, like in Pascal.

* Use late-binding and re-calculate the default every time it is
needed. This risks being expensive, and has its own share of
gotchas.

* If you can somehow determine which values are mutable and which
are not, you might allow default arguments only for immutable
values. Some restrictive languages can do this: Java, with it's
strongly enforced rules for "private" and "protected" members,
and compile-time checks, may be able to do something like this.
And purely functional languages like Haskell simply avoid the
issue by ensuring that *all* values are immutable. But for
Python, it is impossible.


--
Steven
 
Reply With Quote
 
Rick Johnson
Guest
Posts: n/a
 
      06-21-2013
On Friday, June 21, 2013 10:57:17 AM UTC-5, Steven D'Aprano wrote:
> On Thu, 20 Jun 2013 11:05:32 -0700, Rick Johnson wrote:
> > py> class FuncAdd(object):
> > ... def __init__(self, ivalue):
> > ... self.ivalue = ivalue

> Notice how you are storing state here? I thought you said,
> and I quote: "When the subroutine is completed, ALL INPUTS
> and local variables are expected to be destroyed. If the
> programmer wants a return value, he need simply ask. Data
> persistence is NOT a function of subroutines!"
> [emphasis added]
>
> And yet here you are defining persistent input ("ivalue")
> to the callable subroutine, which is stored as external
> state and not destroyed at the end of the subroutine call:


Because Steven, my dear lad, what i created is NOT a
subroutine, no, it's an object that stores state and is
callable. Each call to the object is merely a request to
mutate and then return it's current state. A subroutine, at
least REAL subroutines (not the snake oil that Python is
selling) do not have state.

Real subroutines merely:
1. Optionally take inputs
2. Execute a body of code (which could have side effects,
but which is NOT persistent!)
3. Optionally return output

That's it. If your problem requires state persistence, then
you need to move up to an Object definition. Use the correct
tool for the job dammit!

> > ... def __call__(self, numeric):
> > ... return self.ivalue + numeric
> > ...

> All you have done here is define a subroutine with state,
> precisely the thing that you say subroutines must never
> have.


It's Okay to carry state EXPLICITLY, it's NOT okay to carry
state IMPLICITLY. My implementation is correct, Python's is
not.

Besides, encapsulated state is one of the fundamental
principles of OOP programming, along with interfaces; and
i've satisfied both! The mutable is protected from the world
by an object, and the object allows manipulation of the
mutable via an interface.

But unlike Python's limited implementation, my approach is
scalable. I can change the interface, i can add more
functionality, i can do anything i want.

"I am the Lizard King, and i can do, well ANYTHING!"

However, with Python's limited approach, i'm just a slave to
the implementation. I'm forced to follow estoeric rules with
no chance of scalability.

################################################## ######
# Moral of the Day #
################################################## ######
# You should only use SUBROUTINES for executing #
# subprograms requiring stateless transactions. #
# Alternativly, subprograms requiring persistant state #
# transactions should wield the power of a custom #
# object defintion -- or you can use the #
# global+subroutine method if encapsulation is not #
# warrented. #
################################################## ######

But in any case, following this advice will ensure less bugs
and more maintainable code than Python's current
implementation of lunacy.

> What you haven't done is define a function which takes a
> default value that can be overridden when called.


Oh, you mean like this?

py> class Func(object):
... def __call__(self, arg=0):
... print(arg)
...
py> f = Func()
py> f("pwned")
pwned

> Your argument is invalid.


My argument is not invalid, i just figured i did not need
wipe your bum for you, "Homer". ~(_8^(I)

 
Reply With Quote
 
Rotwang
Guest
Posts: n/a
 
      06-21-2013
On 21/06/2013 18:01, Rick Johnson wrote:
>
> [stuff]


It isn't clear to me from your posts what exactly you're proposing as an
alternative to the way Python's default argument binding works. In your
version of Python, what exactly would happen when I passed a mutable
argument as a default value in a def statement? E.g. this:

>>> a = [1, 2, 3]
>>> a.append(a)
>>> b = object()
>>> def f(x = [None, b, [a, [4]]]):

.... pass # do something

What would you like to see the interpreter do in this case?
 
Reply With Quote
 
Rick Johnson
Guest
Posts: n/a
 
      06-21-2013
On Friday, June 21, 2013 12:47:56 PM UTC-5, Rotwang wrote:
> It isn't clear to me from your posts what exactly you're
> proposing as an alternative to the way Python's default
> argument binding works. In your version of Python, what
> exactly would happen when I passed a mutable argument as a
> default value in a def statement? E.g. this:
>
> >>> a = [1, 2, 3]
> >>> a.append(a)
> >>> b = object()
> >>> def f(x = [None, b, [a, [4]]]):

> ... pass # do something
>
> What would you like to see the interpreter do in this case?


Ignoring that this is a completely contrived example that has
no use in the real world, here are one of three methods by
which i can handle this:

================================================== ==========
The Benevolent Approach:
================================================== ==========
I could cast a "virtual net" over my poor lemmings before
they jump off the cliff by throwing an exception:

Traceback (most recent screw-up last):
Line BLAH in SCRIPT
def f(x = [None, b, [a, [4]]]):
ArgumentError: No mutable default arguments allowed!

================================================== ==========
The Apathetic Approach:
================================================== ==========
I could just assume that a programmer is responsible for the
code he writes. If he passes mutables into a function as
default arguments, and then mutates the mutable later, too
bad, he'll understand the value of writing solid code after
a few trips to exception Hell.

================================================== ==========
The Malevolent Approach (disguised as beneva-loon-icy):
================================================== ==========
I could use early binding to confuse the hell out of him and
enjoy the laughs with all my ivory tower buddies as he falls
into fits of confusion and rage. Then enjoy again when he
reads the docs. Ahh, the gift that just keeps on giving!

================================================== ==========
Conclusion:
================================================== ==========
As you can probably guess the malevolent approach has some
nice fringe benefits.

You know, out of all these post, not one of you guys has
presented a valid use-case that will give validity to the
existence of this PyWart -- at least not one that CANNOT be
reproduced by using my fine examples. All you can muster is
some weak argument about protecting the lemmings.

Is anyone up the challenge?
Does anyone here have any real chops?

PS: I won't be holding my breath.
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      06-21-2013
On Fri, 21 Jun 2013 11:26:39 -0700, Rick Johnson wrote:

> You know, out of all these post, not one of you guys has presented a
> valid use-case that will give validity to the existence of this PyWart


LOL.

Okay, you're trolling. Time for another month in the kill-file.

*plonk*


--
Steven
 
Reply With Quote
 
Chris Angelico
Guest
Posts: n/a
 
      06-21-2013
On Sat, Jun 22, 2013 at 4:26 AM, Rick Johnson
<(E-Mail Removed)> wrote:
> I could cast a "virtual net" over my poor lemmings before
> they jump off the cliff by throwing an exception:
>
> Traceback (most recent screw-up last):
> Line BLAH in SCRIPT
> def f(x = [None, b, [a, [4]]]):
> ArgumentError: No mutable default arguments allowed!


So tell me, oh Great and Powerful Wizard of Rick, how is the
interpreter supposed to know which defaults are mutable? I mean, it's
obviously some intrinsic property of the object. Somehow one thing is
clearly immutable, another thing clearly isn't. Will there be a
PyObject_IsImmutable() API?

Oh! I know. Function argument defaults will now be restricted to
int/float/tuple. That would do it, right? Nobody would be bothered by
little restrictions like that, would they.

ChrisA
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
What value should be passed to make a function use the default argument value? LaundroMat Python 50 10-14-2006 05:11 AM
Default Mozilla isn't default! Help! M. FERRANTE Firefox 1 07-27-2005 09:07 AM
Using default a empty dictionary as a default value C Gillespie Python 3 03-22-2005 12:22 PM
Easy way to output a default value if <xsl:value-of/> selection comes back empty? Michael Ahlers XML 1 07-12-2004 05:17 PM
automatic default route propagation into RIP: default metric Ben Low Cisco 2 12-28-2003 03:57 AM



Advertisments