Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #48742 > unrolled thread

Default Value

Started byAhmed Abdulshafy <abdulshafy@gmail.com>
First post2013-06-19 12:17 -0700
Last post2013-06-20 01:17 +0000
Articles 20 on this page of 86 — 21 participants

Back to article view | Back to comp.lang.python


Contents

  Default Value Ahmed Abdulshafy <abdulshafy@gmail.com> - 2013-06-19 12:17 -0700
    Re: Default Value Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2013-06-19 22:35 +0300
    Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-19 12:38 -0700
      Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 05:57 -0700
        Re: Default Value Roy Smith <roy@panix.com> - 2013-06-20 09:19 -0400
          Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 06:31 -0700
          Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 00:17 +0000
            Re: Default Value Roy Smith <roy@panix.com> - 2013-06-20 20:25 -0400
        Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-20 07:49 -0700
          Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-21 01:38 +1000
            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-20 11:05 -0700
              Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 00:57 +0000
                Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-20 20:16 -0700
                  Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-21 17:10 +1000
                    Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 07:32 -0700
                  Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 16:22 +0000
              Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 15:57 +0000
                Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 10:01 -0700
                  Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-21 18:47 +0100
                    Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 11:26 -0700
                      Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 18:37 +0000
                        Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 12:18 -0700
                          Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 12:35 -0700
                      Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 05:07 +1000
                        Re: Default Value Neil Cerutti <neilc@norwich.edu> - 2013-06-21 19:20 +0000
                          Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 13:27 -0700
                        Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-22 01:31 +0000
                          Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 11:40 +1000
                          Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 18:42 -0700
                          Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-22 03:04 +0100
                            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 19:32 -0700
                              Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-22 20:36 +0100
                              Re: Default Value Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-06-22 18:51 -0400
                            Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-21 19:43 -0700
                          Re: Default Value Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-06-22 09:26 +0100
                      Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-21 20:25 +0100
                        Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 13:44 -0700
                          Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-21 23:49 +0100
                            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 16:51 -0700
                              Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-22 02:54 +0100
                            Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-22 01:15 +0000
                              Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-21 19:27 -0600
                                Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-21 19:32 -0700
                                  Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 19:55 -0700
                                    Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-21 23:23 -0700
                                      Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-22 08:07 -0700
                                        Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-22 08:31 -0700
                                        Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-22 09:11 -0700
                                Re: Default Value Grant Edwards <invalid@invalid.invalid> - 2013-06-24 14:22 +0000
                                  Re: [SPAM] Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-24 16:22 +0100
                              Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 11:41 +1000
                              Re: Default Value Michael Torrie <torriem@gmail.com> - 2013-06-21 20:46 -0600
                              Re: Default Value Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2013-06-22 16:40 +0200
                              Re: Default Value Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-06-22 12:49 -0400
                              Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-22 12:57 -0600
                              Re: Default Value Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-06-22 18:48 -0400
                      Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-22 00:40 +0100
                        Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 18:15 -0700
                          Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 11:37 +1000
                          Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-21 19:42 -0600
                          Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-21 19:38 -0600
                            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 19:40 -0700
                          Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-22 03:01 +0100
                            Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 12:18 +1000
                              Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-22 03:25 +0100
                            Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-22 18:19 +0100
                              Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-22 11:49 -0700
                                Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-23 01:49 +0100
          Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 10:12 -0700
            Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-21 03:19 +1000
              Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 10:30 -0700
            Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-20 11:57 -0600
              Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 11:15 -0700
              Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 01:08 +0000
                Re: Default Value Tim Chase <python.list@tim.thechases.com> - 2013-06-20 20:26 -0500
                  Re: Default Value Roy Smith <roy@panix.com> - 2013-06-20 21:40 -0400
                    Re: Default Value Tim Chase <python.list@tim.thechases.com> - 2013-06-20 21:02 -0500
            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-20 11:07 -0700
              Re: Default Value alex23 <wuwei23@gmail.com> - 2013-06-21 10:55 +1000
            Re: Default Value 88888 Dihedral <dihedral88888@gmail.com> - 2013-06-20 19:18 -0700
            Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 02:26 +0000
            Re: Default Value "Lefavor, Matthew (GSFC-582.0)[MICROTEL LLC]" <matthew.lefavor@nasa.gov> - 2013-06-20 17:28 -0500
              Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 08:17 -0700
          Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 01:28 +0000
    Re: Default Value Gary Herron <gherron@digipen.edu> - 2013-06-19 12:57 -0700
    Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-20 01:17 +0000

Page 1 of 5  [1] 2 3 4 5  Next page →


#48742 — Default Value

FromAhmed Abdulshafy <abdulshafy@gmail.com>
Date2013-06-19 12:17 -0700
SubjectDefault Value
Message-ID<7e6361d5-6619-4aaa-adda-8b5f01bde57f@googlegroups.com>
I'm reading the Python.org tutorial right now, and I found this part rather strange and incomprehensible to me>

Important warning: The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes
def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

This will print
[1]
[1, 2]
[1, 2, 3]

How the list is retained between successive calls? And why?

[toc] | [next] | [standalone]


#48744

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2013-06-19 22:35 +0300
Message-ID<qotvc59evw5.fsf@ruuvi.it.helsinki.fi>
In reply to#48742
Ahmed Abdulshafy <abdulshafy@gmail.com> writes:

> I'm reading the Python.org tutorial right now, and I found this part
> rather strange and incomprehensible to me
> 
> Important warning: The default value is evaluated only once. This
> makes a difference when the default is a mutable object such as a
> list, dictionary, or instances of most classes
>
> def f(a, L=[]):
>     L.append(a)
>     return L
> 
> print(f(1))
> print(f(2))
> print(f(3))
> 
> This will print
> [1]
> [1, 2]
> [1, 2, 3]
> 
> How the list is retained between successive calls? And why?

Functions are objects with their own attributes. The default values
are computed and stored when the def statement is executed.

dir(f) will show the attributes of f. Their names start and end with a
double underscore, __. This indicates that they are not usually used
explicitly. Still, f.__defaults__ seems to be where the default value
is kept between (and during) calls.

[toc] | [prev] | [next] | [standalone]


#48745

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-19 12:38 -0700
Message-ID<b3d90d37-896c-4c80-8f94-9e046453927c@googlegroups.com>
In reply to#48742
On Wednesday, June 19, 2013 2:17:35 PM UTC-5, Ahmed Abdulshafy wrote:
> I'm reading the Python.org tutorial right now, and I found
> this part rather strange and incomprehensible to me>
> 
> Important warning: The default value is evaluated only
> once. This makes a difference when the default is a
> mutable object such as a list, dictionary, or instances of
> most classes
> 
> def f(a, L=[]):
>     L.append(a)
>     return L
> 
> print(f(1))
> print(f(2))
> print(f(3))
> 
> This will print
> 
> [1]
> [1, 2]
> [1, 2, 3]
> 
> How the list is retained between successive calls? And
> why?

By the evil hands of an illogical consistency.

Have you ever heard the old adage: "The road to hell is
paved in good intentions"? Well, apparently the original
designers of the language called in sick the day that class
was taught. It's unfortunate because the same functionality
that this "intention" claims to solve can be reproduced
easily, and in a less astonishing manner, by the programmer
himself.

  http://en.wikipedia.org/wiki/Principle_of_least_astonishment
  

[toc] | [prev] | [next] | [standalone]


#48786

Fromrusi <rustompmody@gmail.com>
Date2013-06-20 05:57 -0700
Message-ID<447dd1c6-1bb2-4276-a109-78d7a067b442@d8g2000pbe.googlegroups.com>
In reply to#48745
On Jun 20, 12:38 am, Rick Johnson <rantingrickjohn...@gmail.com>
wrote:
> On Wednesday, June 19, 2013 2:17:35 PM UTC-5, Ahmed Abdulshafy wrote:
> > I'm reading the Python.org tutorial right now, and I found
> > this part rather strange and incomprehensible to me>
>
> > Important warning: The default value is evaluated only
> > once. This makes a difference when the default is a
> > mutable object such as a list, dictionary, or instances of
> > most classes
>
> > def f(a, L=[]):
> >     L.append(a)
> >     return L
>
> > print(f(1))
> > print(f(2))
> > print(f(3))
>
> > This will print
>
> > [1]
> > [1, 2]
> > [1, 2, 3]
>
> > How the list is retained between successive calls? And
> > why?
>
> By the evil hands of an illogical consistency.
>
> Have you ever heard the old adage: "The road to hell is
> paved in good intentions"? Well, apparently the original
> designers of the language called in sick the day that class
> was taught. It's unfortunate because the same functionality
> that this "intention" claims to solve can be reproduced
> easily, and in a less astonishing manner, by the programmer
> himself.
>
>  http://en.wikipedia.org/wiki/Principle_of_least_astonishment


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

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.
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
Heres a correction suggestion: http://mail.python.org/pipermail/python-ideas/2007-January/000073.html
Here's Terry Reedy's nicely explaining the 'why-of-the-how' :
http://mail.python.org/pipermail/python-ideas/2009-May/004680.html

FWIW here is a conceptual/philosophical explanation of your confusion:

There are 2 fundamental ways for approaching the programming task --
functional and imperative.
In FP, the primary requirement is that the behavior of a function
should be entirely determinable by its arguments.
In Imp. P, computation proceeds by changing state.

Now from the time of Backus turing award http://amturing.acm.org/award_winners/backus_0703524.cfm
it is known that the two philosophies are mutually incompatible.  Now
python is in a rather unique position in this respect: it supports
many of the features of modern FPLs and one can almost do functional
programming in it.  In a few cases the imperative/Object-based
internals leak out, this is one of those cases.

That such leakage will occasionally happen see:
http://www.joelonsoftware.com/articles/LeakyAbstractions.html

And you've had a little excess of the FP koolaid read :
http://blog.languager.org/2012/08/functional-programming-philosophical.html

[toc] | [prev] | [next] | [standalone]


#48787

FromRoy Smith <roy@panix.com>
Date2013-06-20 09:19 -0400
Message-ID<roy-5EEFF8.09194820062013@news.panix.com>
In reply to#48786
In article 
<447dd1c6-1bb2-4276-a109-78d7a067b442@d8g2000pbe.googlegroups.com>,
 rusi <rustompmody@gmail.com> 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.

[toc] | [prev] | [next] | [standalone]


#48789

Fromrusi <rustompmody@gmail.com>
Date2013-06-20 06:31 -0700
Message-ID<011effa3-7afa-4744-a5fe-07d10b1fc059@v5g2000pbv.googlegroups.com>
In reply to#48787
On Jun 20, 6:19 pm, Roy Smith <r...@panix.com> wrote:
> In article
> <447dd1c6-1bb2-4276-a109-78d7a067b...@d8g2000pbe.googlegroups.com>,
>
>  rusi <rustompm...@gmail.com> 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.

See http://www.cs.utexas.edu/~EWD/transcriptions/EWD04xx/EWD480.html
(search forward to 'disastrous blending' )
No I am not saying that such knowledge is not required in the 'real
world'

However I do feel that just as a view of literature that does not go
beyond gothic horror is a poor view;
and just because for languages like C (even more C++) expertise more
or less equivales gothicness,
for a cleaner world like python we should distinguish the seedy areas
we know about but avoid and the clean areas we live in.
Clearly flagging gotchas as such helps in that direction.

In short (and to the OP): If you did NOT find this confusing, it would
be cause for more concern :-)

[toc] | [prev] | [next] | [standalone]


#48829

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-06-21 00:17 +0000
Message-ID<51c39b88$0$29999$c3e8da3$5496439d@news.astraweb.com>
In reply to#48787
On Thu, 20 Jun 2013 09:19:48 -0400, Roy Smith wrote:

> In article
> <447dd1c6-1bb2-4276-a109-78d7a067b442@d8g2000pbe.googlegroups.com>,
>  rusi <rustompmody@gmail.com> 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

[toc] | [prev] | [next] | [standalone]


#48830

FromRoy Smith <roy@panix.com>
Date2013-06-20 20:25 -0400
Message-ID<roy-AEF116.20253620062013@news.panix.com>
In reply to#48829
In article <51c39b88$0$29999$c3e8da3$5496439d@news.astraweb.com>,
 Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:

> On Thu, 20 Jun 2013 09:19:48 -0400, Roy Smith wrote:
> 
> > In article
> > <447dd1c6-1bb2-4276-a109-78d7a067b442@d8g2000pbe.googlegroups.com>,
> >  rusi <rustompmody@gmail.com> 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.

[toc] | [prev] | [next] | [standalone]


#48796

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-20 07:49 -0700
Message-ID<2e92b4c7-31be-40d2-a906-ab19f3630dfa@googlegroups.com>
In reply to#48786
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!"

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

[toc] | [prev] | [next] | [standalone]


#48802

FromChris Angelico <rosuav@gmail.com>
Date2013-06-21 01:38 +1000
Message-ID<mailman.3627.1371742717.3114.python-list@python.org>
In reply to#48796
On Fri, Jun 21, 2013 at 12:49 AM, Rick Johnson
<rantingrickjohnson@gmail.com> wrote:
> 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!

Funny, C violates your description too.

int counter()
{
    static int count;
    return ++count;
}

Function defaults in Python, being implemented as attributes on the
function object, are very similar in nature to static variables in C.
They're constructed once at function creation time, they're available
to that function (okay, C doesn't have any concept of "reaching into"
a function from the outside, Python does), they out-last any
particular execution of that function.

> Finally, a subroutine
> should never have side effects UNLESS the programmer
> explicitly ask for a side effect.

Bogus.

http://www.postgresql.org/docs/current/static/sql-createfunction.html

By default, a function is assumed to have side effects. The
programmer/sysadmin has to explicitly ask for PostgreSQL to treat the
function as NOT having side effects (the IMMUTABLE attribute, or
possibly its weaker cousin STABLE).

ChrisA

[toc] | [prev] | [next] | [standalone]


#48817

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-20 11:05 -0700
Message-ID<baf4de3c-e4ff-42c0-8d65-2f6cf825735c@googlegroups.com>
In reply to#48802
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.

[toc] | [prev] | [next] | [standalone]


#48832

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-06-21 00:57 +0000
Message-ID<51c3a4f8$0$29999$c3e8da3$5496439d@news.astraweb.com>
In reply to#48817
On Thu, 20 Jun 2013 11:05:32 -0700, Rick Johnson wrote:

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

If only that were true, but I fear that you're just looking for an 
argument.


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

Even if Python chose late binding instead of early binding for function 
defaults, the default would *still* need to be stored somewhere. 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.


> 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. 99% of the time a function will 
do the job more easily, especially now that Python supports closures.


[...]
> 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. 
"Global variables considered harmful" has been a well-known principle of 
programming dating back to the 1970s.


> 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? Programmers who are experienced with some other language but have 
no clue about what these weird __init__ and __call__ methods do? 
Programmers with 40 years experience who don't know anything about object-
oriented code? People who have been immersed in Python coding for 15 
years? Every feature is confusing to *some* people and not others.


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

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

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


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


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

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

- it's easy to get late binding semantics starting with early 
  binding, but more difficult to go the other way.

- simplicity of implementation: late binding requires that 
  Python store, not the result of the expression, but the 
  expression itself (together with a context) for later 
  evaluation; early binding simply requires that the expression
  is evaluated at runtime, like any other expression.


That's not to say that there are no arguments in favour of late binding. 
But on balance, despite the odd sharp corner, I believe that early 
binding's benefits far outweigh its gotchas.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#48843

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-20 20:16 -0700
Message-ID<b1ef7774-b733-4d5c-85b3-dc1c5a8c4a3e@googlegroups.com>
In reply to#48832
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.

[toc] | [prev] | [next] | [standalone]


#48847

FromChris Angelico <rosuav@gmail.com>
Date2013-06-21 17:10 +1000
Message-ID<mailman.3655.1371798652.3114.python-list@python.org>
In reply to#48843
On Fri, Jun 21, 2013 at 1:16 PM, Rick Johnson
<rantingrickjohnson@gmail.com> 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

[toc] | [prev] | [next] | [standalone]


#48863

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-21 07:32 -0700
Message-ID<f7ec7e3d-fbc2-4e5d-a38b-adcaedd12a09@googlegroups.com>
In reply to#48847
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!

[toc] | [prev] | [next] | [standalone]


#48869

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-06-21 16:22 +0000
Message-ID<51c47db9$0$29999$c3e8da3$5496439d@news.astraweb.com>
In reply to#48843
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

[toc] | [prev] | [next] | [standalone]


#48867

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-06-21 15:57 +0000
Message-ID<51c477dd$0$29999$c3e8da3$5496439d@news.astraweb.com>
In reply to#48817
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

[toc] | [prev] | [next] | [standalone]


#48870

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-21 10:01 -0700
Message-ID<565a1c8f-6fd9-4bab-9834-076eaea527f8@googlegroups.com>
In reply to#48867
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)

[toc] | [prev] | [next] | [standalone]


#48871

FromRotwang <sg552@hotmail.co.uk>
Date2013-06-21 18:47 +0100
Message-ID<kq23at$i39$1@dont-email.me>
In reply to#48870
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?

[toc] | [prev] | [next] | [standalone]


#48872

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-21 11:26 -0700
Message-ID<7e1ed740-df18-4978-b11d-8ca9c4b5bd04@googlegroups.com>
In reply to#48871
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.

[toc] | [prev] | [next] | [standalone]


Page 1 of 5  [1] 2 3 4 5  Next page →

Back to top | Article view | comp.lang.python


csiph-web