Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Default Value

Reply
Thread Tools

Default Value

 
 
rusi
Guest
Posts: n/a
 
      06-20-2013
You know Rick, you are good at python, you are better at polemics.
If only you would cut the crap I would (be able to) agree with you.
See below

On Jun 20, 7:49*pm, Rick Johnson <(E-Mail Removed)> wrote:
> On Thursday, June 20, 2013 7:57:06 AM UTC-5, rusi wrote:
> > Every language has gotchas. This is one of python's.

>
> So are we purposely injecting illogic into our language just
> to be part of some "cool crowd" of programming languages with
> gotchas.
>
> *"You thought intuitiveness was a virtue? Haha, we gotcha!"



Python (and all the other 'cool' languages) dont have gotchas because
someone malevolently put them there.
In most cases, the problem is seen too late and the cost of changing
entrenched code too great.
Or the problem is clear, the solution is not etc etc.

>
> Or maybe this is reminiscent of the fraternity hazing rituals
> of days gone by:
>
> **POP*
> *"Thank you Sir, may i have another?"
>
> > If you are a beginning python programmer, really the best
> > answer is: Just dont do it! *Dont do what? Dont use
> > mutable arguments as function defaults. Once you cross the
> > noob stage you can check that its a standard gotcha: Just
> > run a search for 'python gotcha default []'

>
> > And when you feel that you need to, use Steven's trick:
> > use a immutable indicator 'None' for the mutable []. Once
> > you cross the noob stage you can check that its a standard
> > gotcha: Just run a search for 'python gotcha default []'
> > Its even been discussed repeatedly on the python-ideas
> > list

>
> Your attempting to excuse an inexcusable language flaw by
> pointing out that the effects of the flaw can be avoided by
> using a workaround. And, to add insult to injury, you
> provide no good reason for the flaw to exist:
>
> *"Just do x, y, and z and shut up. Yes we made a mistake
> *but we are not about to admit our mistake and the onerous
> *will be on all the noobs to re-invent the workaround each
> *time"
>
> To me that is unacceptable.
>
> > Heres a correction suggestion: [...] Here's Terry Reedy's
> > nicely explaining the 'why-of-the-how' : [...] FWIW here
> > is a conceptual/philosophical explanation of your
> > confusion: There are 2 fundamental ways for approaching
> > the programming task -- functional and imperative.

>
> All these "explanations" ignore a fundamental fact about
> subroutines[1].


>
> A call to a subroutine should exists as a unique transaction
> within the entire program. It is expected to optionally take
> inputs, and optionally return an output (depending on the
> definition).
>
> 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! Finally, a subroutine
> should never have side effects UNLESS the programmer
> explicitly ask for a side effect.
>
> However, the Python flaw of allowing mutable sequence
> arguments to persist between successive calls of a
> subroutine is breaking the entire definition of a
> subroutine, and for what noble purpose i ask? What purpose
> is SO important that you change a well established interface
> in a totally unintuitive manner?
>
> If your answer is that recursion is easier, then i say that
> is foolish because a programmer can keep a reference
> to a mutable sequence OUTSIDE the subroutine and you can
> save the "gotchas" for Guido's next birthday party.
>
> [1]:http://en.wikipedia.org/wiki/Subroutine



You are saying in different language what I said: Functional
programming is a good idea, imperative programming is a bad idea.
From the invention of subroutines (ie 50 years) PL designers are
hearing this truth but somehow or other fail to listen; for more
details see http://blog.languager.org/2012/11/im...ssons-not.html
 
Reply With Quote
 
 
 
 
Chris Angelico
Guest
Posts: n/a
 
      06-20-2013
On Fri, Jun 21, 2013 at 3:12 AM, rusi <(E-Mail Removed)> wrote:
> Python (and all the other 'cool' languages) dont have gotchas because
> someone malevolently put them there.
> In most cases, the problem is seen too late and the cost of changing
> entrenched code too great.
> Or the problem is clear, the solution is not etc etc.


Or, in many MANY cases, the choice was the right one, but isn't
obvious to everyone.

ChrisA
 
Reply With Quote
 
 
 
 
rusi
Guest
Posts: n/a
 
      06-20-2013
On Jun 20, 10:19*pm, Chris Angelico <(E-Mail Removed)> wrote:
> On Fri, Jun 21, 2013 at 3:12 AM, rusi <(E-Mail Removed)> wrote:
> > Python (and all the other 'cool' languages) dont have gotchas because
> > someone malevolently put them there.
> > In most cases, the problem is seen too late and the cost of changing
> > entrenched code too great.
> > Or the problem is clear, the solution is not etc etc.

>
> Or, in many MANY cases, the choice was the right one, but isn't
> obvious to everyone.
>
> ChrisA


Ha!

If you've ever taught a first programming class you would know how
frequent is the complaint (said by a beginning student in a loud
confident voice): THE COMPILER HAS A BUG!
 
Reply With Quote
 
Ian Kelly
Guest
Posts: n/a
 
      06-20-2013
On Thu, Jun 20, 2013 at 11:19 AM, Chris Angelico <(E-Mail Removed)> wrote:
> On Fri, Jun 21, 2013 at 3:12 AM, rusi <(E-Mail Removed)> wrote:
>> Python (and all the other 'cool' languages) dont have gotchas because
>> someone malevolently put them there.
>> In most cases, the problem is seen too late and the cost of changing
>> entrenched code too great.
>> Or the problem is clear, the solution is not etc etc.

>
> Or, in many MANY cases, the choice was the right one, but isn't
> obvious to everyone.


I think it's worth pointing out that changing function defaults to
late-binding would merely change the nature of the gotcha, not eliminate it.

words = ("one", "two", "red", "blue", "fish")

def join_strings(strings=words):
return ' '.join('%s %s' % (s, strings[-1]) for s in strings[:-1])

# Later:
words = open("gettysburg_address.txt", "r").read().split()
# Oops, the default argument of join_strings just changed.


Additionally, with late-binding semantics the default values would no
longer be default *values*. They would be initialization code
instead, which sort of flies in the face of the idea that late-binding
would somehow be better for functional programming -- if the default
expressions have no side effects and since they don't depend on the
function arguments, why should they need to run more than once? If
the goal is indeed to make the the functions more functional, then the
proper solution would be to keep the binding early but just disallow
mutable defaults altogether -- which is tricky to achieve in Python,
so we simply emulate it with the advice "don't use mutable function
defaults".
 
Reply With Quote
 
Rick Johnson
Guest
Posts: n/a
 
      06-20-2013
On Thursday, June 20, 2013 10:38:34 AM UTC-5, Chris Angelico wrote:
> Function defaults in Python, being implemented as
> attributes on the function object, are very similar in
> nature to static variables in C.


Oh wait a minute. i think it's becoming clear to me now!

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
... def __call__(self, numeric):
... return self.ivalue + numeric
...
py> fa = FuncAdd(10)
py> fa(10)
20
py> fa(20)
30

I can even emulate (quite easily) this idea of
"persistence of function arguments" with mutables
too, Yippee!

py> class ArgPersist(object):
... def __init__(self, lst):
... self.lst = lst
... def __call__(self, arg):
... self.lst.append(arg)
... return self.lst
...
py> fp = ArgPersist([1,2,3])
py> fp(4)
[1, 2, 3, 4]
py> fp([5,6,7])
[1, 2, 3, 4, [5, 6, 7]]

But then, i can even do it WITHOUT creating an object
definition:

py> mutable = []
py> def expandMutable(arg):
... mutable.append(arg)
...
py> expandMutable(1)
py> mutable
[1]
py> expandMutable([2,3,4])
py> mutable
[1, [2, 3, 4]]

ANY of those approaches are much less confusing than the
current flaw and do not violate the least astonishment law..
I'm quite Okay with Python functions being first class
objects, however, i am not okay with violating the
fundamental nature of subroutines, especially when that
violation can offer no clear and arguable benefits and is in
fact unreasonably esoteric in nature.
 
Reply With Quote
 
Rick Johnson
Guest
Posts: n/a
 
      06-20-2013
On Thursday, June 20, 2013 12:12:01 PM UTC-5, rusi wrote:

> Python (and all the other 'cool' languages) dont have
> gotchas because someone malevolently put them there. In
> most cases, the problem is seen too late and the cost of
> changing entrenched code too great.


Okay. So now you are admitting the problem. That is a good
start. Thanks for being honest.

> Or the problem is clear, the solution is not etc etc.


Both the problem and solution are clear, however, the will to execute
the solution remains to be seem. Are you telling me we can
justify breaking backwards compatibility for the sake of
"print"[1] but we cannot justify breaking it for this
monstrosity? Come on Rusi, you've gone too far with the
comedy now.

[1]: FYI I personally think print as function is the correct implementation.
 
Reply With Quote
 
rusi
Guest
Posts: n/a
 
      06-20-2013
On Jun 20, 10:57*pm, Ian Kelly <(E-Mail Removed)> wrote:
> If
> the goal is indeed to make the the functions more functional, then the
> proper solution would be to keep the binding early but just disallow
> mutable defaults altogether -- which is tricky to achieve in Python,
> so we simply emulate it with the advice "don't use mutable function
> defaults".



Nicely put. "Imperative programming is a bad idea; FP is a good idea"
is an attractive religious dogma.
When put into practice with full religious zeal, we then need
something like monads to make realistic programming possible.
Which then becomes a case of "remedy worse than disease".

Which is why I prefer to keep FP in the limbo region between ideology
and technology
 
Reply With Quote
 
Lefavor, Matthew (GSFC-582.0)[MICROTEL LLC]
Guest
Posts: n/a
 
      06-20-2013
Or, in many MANY cases, the choice was the right one, but isn't
obvious to everyone.

I think it's worth pointing out that changing function defaults to
late-binding would merely change the nature of the gotcha, not eliminate it..

words = ("one", "two", "red", "blue", "fish")

def join_strings(strings=words):
return ' '.join('%s %s' % (s, strings[-1]) for s in strings[:-1])

# Later:
words = open("gettysburg_address.txt", "r").read().split()
# Oops, the default argument of join_strings just changed.

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

I, for one, would much rather follow the rule "don't use mutable arguments in function definitions" than "don't ever re-use the name of your variables.."

ML

 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      06-21-2013
On Thu, 20 Jun 2013 09:19:48 -0400, Roy Smith wrote:

> In article
> <(E-Mail Removed)>,
> rusi <(E-Mail Removed)> wrote:
>
>> > > def f(a, L=[]):
>> > > * * L.append(a)
>> > > * * return L

>
>> Every language has gotchas. This is one of python's.

>
> One of our pre-interview screening questions for Python programmers at
> Songza is about this. I haven't been keeping careful statistics, but
> I'd guess only about 50% of the candidates get this right.



What exactly is the question? Because it's not always a bug to use a
mutable default, there are good uses for it:


def func(arg, cache={}):
...


Now you can pass your own cache as an argument, otherwise the function
will use the default. The default cache is mutable, and so will remember
values from one invocation to the next.


--
Steven
 
Reply With Quote
 
Roy Smith
Guest
Posts: n/a
 
      06-21-2013
In article <51c39b88$0$29999$c3e8da3$(E-Mail Removed) om>,
Steven D'Aprano <(E-Mail Removed)> wrote:

> On Thu, 20 Jun 2013 09:19:48 -0400, Roy Smith wrote:
>
> > In article
> > <(E-Mail Removed)>,
> > rusi <(E-Mail Removed)> wrote:
> >
> >> > > def f(a, L=[]):
> >> > > * * L.append(a)
> >> > > * * return L

> >
> >> Every language has gotchas. This is one of python's.

> >
> > One of our pre-interview screening questions for Python programmers at
> > Songza is about this. I haven't been keeping careful statistics, but
> > I'd guess only about 50% of the candidates get this right.

>
>
> What exactly is the question? Because it's not always a bug to use a
> mutable default, there are good uses for it:


It's a screening question; I'd rather not reveal all the details (it's
really annoying when you find your screening questions posted to stack
overflow). But, yes, I understand that there are good uses.
 
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