473,406 Members | 2,620 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

default value in __init__

Dear all,

I have encountered this weird problem.

I have a class definition with an __init__ argument 'd'
which defaults to {}. This argument is put in the 'self.d'
attribute at initialization

I create two independent instances of this class; the code
is as follows.

class C:
def __init__(self, i=10, d = {}):
self.d = d
self.i = i
def get(self):
print
print self.d
def set(self, dval, ival):
self.d.update(dval)
self.i+=ival

c1=C()
c1.set({'one':1},3)
c1.get()

del c1

c2=C()
c2.set({'two':2},4)
c2.get()
If I run the code I obtain:

{'one': 1}

{'two': 2, 'one': 1}

It seems that the 'self.d' argument of the second instance is the
same of the 'self.d' of the first (deleted!) instance.

Running the code in a debugger I discovered that, when I enter the
__init__ at the second initialization, before doing

self.d = d

the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.

Am I doing some stupid error, or this is a problem ?

Thanks in advance for any help,
Paolo
Oct 9 '08 #1
43 3161
See Pitfall #5 on http://zephyrfalcon.org/labs/python_pitfalls.html
It also applies to dictionaries (and sets, any mutable object really).

On Thu, Oct 9, 2008 at 1:03 AM, kenneth <ke*****@inwind.itwrote:
Dear all,

I have encountered this weird problem.

I have a class definition with an __init__ argument 'd'
which defaults to {}. This argument is put in the 'self.d'
attribute at initialization

I create two independent instances of this class; the code
is as follows.

class C:
def __init__(self, i=10, d = {}):
Change 'd = {}' to 'd=None'
Add the line:
if d is None: d = {}

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
self.d = d
self.i = i
def get(self):
print
print self.d
def set(self, dval, ival):
self.d.update(dval)
self.i+=ival

c1=C()
c1.set({'one':1},3)
c1.get()

del c1

c2=C()
c2.set({'two':2},4)
c2.get()
If I run the code I obtain:

{'one': 1}

{'two': 2, 'one': 1}

It seems that the 'self.d' argument of the second instance is the
same of the 'self.d' of the first (deleted!) instance.

Running the code in a debugger I discovered that, when I enter the
__init__ at the second initialization, before doing

self.d = d

the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.

Am I doing some stupid error, or this is a problem ?

Thanks in advance for any help,
Paolo
--
http://mail.python.org/mailman/listinfo/python-list
Oct 9 '08 #2
kenneth wrote:
the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.

Am I doing some stupid error, or this is a problem ?
No, it always contains the default argument because default values are
created just ONE TIME.
http://effbot.org/pyfaq/why-are-defa...en-objects.htm

Oct 9 '08 #3
On Oct 9, 10:14*am, Christian Heimes <li...@cheimes.dewrote:
kenneth wrote:
the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.
Am I doing some stupid error, or this is a problem ?

No, it always contains the default argument because default values are
created just ONE TIME.http://effbot.org/pyfaq/why-are-defa...etween-objects...

Wow, it's a very "dangerous" behavior ...

Just to know, is this written somewhere in the python documentation or
one has to discover it when his programs fails to work ;-) ?

Paolo
Oct 9 '08 #4
On Thu, Oct 9, 2008 at 1:39 AM, kenneth <ke*****@inwind.itwrote:
On Oct 9, 10:14 am, Christian Heimes <li...@cheimes.dewrote:
>kenneth wrote:
the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.
Am I doing some stupid error, or this is a problem ?

No, it always contains the default argument because default values are
created just ONE TIME.http://effbot.org/pyfaq/why-are-defa...etween-objects...


Wow, it's a very "dangerous" behavior ...

Just to know, is this written somewhere in the python documentation or
one has to discover it when his programs fails to work ;-) ?
It's mentioned in the tutorial (note the "Important warning"):
http://docs.python.org/tutorial/cont...rgument-values

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
>
Paolo
--
http://mail.python.org/mailman/listinfo/python-list
Oct 9 '08 #5
In article
<5f**********************************@v53g2000hsa. googlegroups.com>,
kenneth <ke*****@inwind.itwrote:
On Oct 9, 10:14*am, Christian Heimes <li...@cheimes.dewrote:
kenneth wrote:
the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.
Am I doing some stupid error, or this is a problem ?
No, it always contains the default argument because default values are
created just ONE
TIME.http://effbot.org/pyfaq/why-are-defa...etween-objects..
.


Wow, it's a very "dangerous" behavior ...

Just to know, is this written somewhere in the python documentation or
one has to discover it when his programs fails to work ;-) ?
At least once a week someone discovers this "problem", makes a
post about it here, and then someone points to the spot in the
documentation where it's explained.

Seems to me that people often site the "important warning" in
the tutorial. Of course there's no reason anyone would bother
going through the tutorial - just for fun I looked in the
official Python Reference Manual to see whether they're explicit
about this or require the reader to figure it out from something
else they say.

There's a section titled "7.6 Function definitions". About halfway
through that section there's a _bold face_ statement
"Default parameter values are evaluated when the function definition is
executed.", followed by an explanation of how that can lead to
the sort of problem above.

So I guess it _is_ awfully dangerous. They should really explain
this aspect of the language's behavior to people who don't read
the formal definition and also don't work through the tutorial.

Paolo
--
David C. Ullrich
Oct 9 '08 #6
David C. Ullrich a écrit :
In article
<5f**********************************@v53g2000hsa. googlegroups.com>,
kenneth <ke*****@inwind.itwrote:
>On Oct 9, 10:14 am, Christian Heimes <li...@cheimes.dewrote:
>>kenneth wrote:
the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.
Am I doing some stupid error, or this is a problem ?
No, it always contains the default argument because default values are
created just ONE
TIME.http://effbot.org/pyfaq/why-are-defa...etween-objects..
.

Wow, it's a very "dangerous" behavior ...

Just to know, is this written somewhere in the python documentation or
one has to discover it when his programs fails to work ;-) ?

At least once a week someone discovers this "problem", makes a
post about it here, and then someone points to the spot in the
documentation where it's explained.

Seems to me that people often site the "important warning" in
the tutorial. Of course there's no reason anyone would bother
going through the tutorial
Indeed. No reason at all.
- just for fun I looked in the
official Python Reference Manual to see whether they're explicit
about this or require the reader to figure it out from something
else they say.

There's a section titled "7.6 Function definitions". About halfway
through that section there's a _bold face_ statement
"Default parameter values are evaluated when the function definition is
executed.", followed by an explanation of how that can lead to
the sort of problem above.
But there's no reason to read the reference manual neither.
So I guess it _is_ awfully dangerous. They should really explain
this aspect of the language's behavior to people who don't read
the formal definition and also don't work through the tutorial.
You mean : "to people that don't bother reading the FineManual *nor*
searching the newsgroup / ML archives ?"

Well... How to say.. Is there any chance these people will read anything
*at all* ?
Oct 10 '08 #7
Bruno Desthuilliers:
You mean : "to people that don't bother reading the FineManual *nor*
searching the newsgroup / ML archives ?"
Are there ways to change how Python3 manages arguments and functions,
to remove this antifeature of Python, avoiding this common mistake
done by every newbie?
I don't care if it reduces the performance of Python a little.

Bye,
bearophile
Oct 10 '08 #8
be************@lycos.com wrote:
Bruno Desthuilliers:
>You mean : "to people that don't bother reading the FineManual *nor*
searching the newsgroup / ML archives ?"

Are there ways to change how Python3 manages arguments and functions,
to remove this antifeature of Python, avoiding this common mistake
done by every newbie?
I don't care if it reduces the performance of Python a little.
You can't just copy the default values on every call: you would still get
people confused by the semantics whether you did a shallow or deep copy or
as now no copy. I don't think simply re-executing the default argument
expression on each call works either: that would confuse at least as many
people as the current system.

It would be possible, but extremely annoying to limit default arguments to
being literal constants, or slightly less drastically limit them to being
of types known to be immutable. Of course that blocks you from using any
user defined types unless you invent some kind of scheme for declaring that
a type is safe to use as a default argument.

Another option might just be to generate a warning the first time a program
uses a not obviously immutable default.

I think in this situation the best solution is to expect people to learn to
use the language, and accept that those people who don't RTFM will keep on
asking here. Even if you could change the behaviour of default arguments we
would still get equivalent regular questions from the people who initialise
class attributes with lists or dictionaries.

--
Duncan Booth http://kupuguy.blogspot.com
Oct 10 '08 #9
Duncan Booth:
You can't just copy the default values on every call: you would still get
people confused by the semantics whether you did a shallow or deep copy or
as now no copy.
I think I agree.

I don't think simply re-executing the default argument
expression on each call works either: that would confuse at least as many
people as the current system.
May I ask you why? I think I don't agree, but I am not sure.

It would be possible, but extremely annoying to limit default arguments to
being literal constants,
This is a possible solution, beside re-executing the default argument
expression on each call.

unless you invent some kind of scheme for declaring that
a type is safe to use as a default argument.
Well, it seems functional-style programming may become more common in
the future, and seeing languages like Scala, etc, maybe it can be
useful to add to Python some way to define immutable classes (in an
explicit way). Maybe subclasses of Immutable?

Another option might just be to generate a warning the first time a program
uses a not obviously immutable default.
I don't like this solution much.

Even if you could change the behaviour of default arguments we
would still get equivalent regular questions from the people who initialise
class attributes with lists or dictionaries.
I have seen professional programmers too use class attributes instead
of instance ones...

Well, you can't create a fool-proof language that is useful too, but
in a language that is designed for new programmers too, like Python,
and that doesn't put the running speed as its most important feature,
then I think patching the most known and common pitfalls/traps is
useful, even if you can't patch them all (without turning the language
into something useless).

Bye,
bearophile
Oct 10 '08 #10
On Fri, Oct 10, 2008 at 4:36 AM, <be************@lycos.comwrote:
Bruno Desthuilliers:
>You mean : "to people that don't bother reading the FineManual *nor*
searching the newsgroup / ML archives ?"

Are there ways to change how Python3 manages arguments and functions,
to remove this antifeature of Python, avoiding this common mistake
done by every newbie?
I don't care if it reduces the performance of Python a little.
The general idea been discussed ad-nauseum on the list several times
before, including just 2 months ago. See e.g.:

[Python-3000] default argument surprises
http://mail.python.org/pipermail/pyt...st/014658.html

[Python-ideas] proto-PEP: Fixing Non-constant Default Arguments
http://mail.python.org/pipermail/pyt...ry/000121.html

[Python-3000] pre-PEP: Default Argument Expressions
http://mail.python.org/pipermail/pyt...ry/005704.html

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
>
Bye,
bearophile
--
http://mail.python.org/mailman/listinfo/python-list
Oct 10 '08 #11
be************@lycos.com wrote:
>I don't think simply re-executing the default argument
expression on each call works either: that would confuse at least as
many people as the current system.

May I ask you why? I think I don't agree, but I am not sure.
My thought (which may well be wrong) is that people would still expect the
default argument expression to use the values of variables at the time when
the function is defined, not the values at the point of calling it.

e.g. in this hypothetical universe:
>>y = 0
def f(x=y): return x*x
>>y = 1
f()
1

would certainly be suprising to anyone used to the current behaviour and I
think would also suprise anyone who hadn't read the manual in sufficient
details.

We already get people asking why code like this doesn't return 3:
>>fns = [ lambda: x for x in range(10) ]
fns[3]()
9

i.e. they expect the variable lookup to be done at function definition time
rather than function call time. This implies to me that some people are
going to get confused whichever way round these things happen although
perhaps it is the behaviour of default arguments that makes them expect
this.

As an aside, making this change to default arguments would mean the
solution usually proposed to the function scoping question above would no
longer work:
>>fns = [ lambda y=x: y for x in range(10) ]
fns[3]()
3

I wonder whether it is the way the default argument expressions are
embedded inside the function that causes the confusion? If for example
default arguments were defined like this:

class C:
@default(d={})
def __init__(self, i=10, d):
self.d = d
self.i = i

would moving the expression before the 'def' make people less inclined to
be suprised that the object is shared?
Oct 10 '08 #12
Chris Rebert:
The general idea been discussed ad-nauseum on the list several times
before, including just 2 months ago. See e.g.:
Okay, it can't be fixed then.

Bye and thank you,
bearophile
Oct 10 '08 #13
On Thu, 09 Oct 2008 01:39:30 -0700, kenneth (a.k.a. Paolo) wrote:
On Oct 9, 10:14Â*am, Christian Heimes <li...@cheimes.dewrote:
>kenneth wrote:
the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.
Am I doing some stupid error, or this is a problem ?

No, it always contains the default argument because default values are
created just ONE
TIME.http://effbot.org/pyfaq/why-are-defa...hared-between-
objects...
>

Wow, it's a very "dangerous" behavior ...
No, it's very *useful* behaviour.
--
Steven
Oct 11 '08 #14
On Fri, 10 Oct 2008 06:20:35 -0700, bearophileHUGS wrote:
>I don't think simply re-executing the default argument expression on
each call works either: that would confuse at least as many people as
the current system.

May I ask you why? I think I don't agree, but I am not sure.
x = 100
def foo(a, b=x):
return a+b

first = foo(1)
x = 101
second = foo(1)

assert first == second
I think people will be rightly surprised that this fails.

>It would be possible, but extremely annoying to limit default arguments
to being literal constants,

This is a possible solution, beside re-executing the default argument
expression on each call.
That's no solution at all, because default arguments should not be
limited to literal constants. That's unacceptable in my opinion.
>unless you invent some kind of scheme for declaring that a type is safe
to use as a default argument.

Well, it seems functional-style programming may become more common in
the future, and seeing languages like Scala, etc, maybe it can be useful
to add to Python some way to define immutable classes (in an explicit
way). Maybe subclasses of Immutable?
You're still assuming that the behaviour is a bug. It's not, it's a
feature.

>Even if you could change the behaviour of default arguments we would
still get equivalent regular questions from the people who initialise
class attributes with lists or dictionaries.

I have seen professional programmers too use class attributes instead of
instance ones...
That's only a mistake if you don't mean to use class attributes instead
of instance attributes.

--
Steven
Oct 11 '08 #15
On Oct 10, 12:30*pm, Duncan Booth <duncan.bo...@invalid.invalid>
wrote:
bearophileH...@lycos.com wrote:
I don't think simply re-executing the default argument
expression on each call works either: that would confuse at least as
many people as the current system.
May I ask you why? I think I don't agree, but I am not sure.
(snip)
I wonder whether it is the way the default argument expressions are
embedded inside the function that causes the confusion? If for example
default arguments were defined like this:

class C:
* @default(d={})
* def __init__(self, i=10, d):
* * self.d = d
* * self.i = i

would moving the expression before the 'def' make people less inclined to
be suprised that the object is shared?
You could of course define a wrapper to do call-time assignment:

@calltime( d= dict, e= tuple )
def foo( self, d, e ):

If this decorator appeared in the standard library, newbies would be
able to stumble upon it.

I don't think either semantic is more obvious from the syntax alone.
It could mean either thing just as reasonably, and if Python defined
the opposite, we'd be getting opposite complaints.

On one hand, note that the return statement does not follow the same
convention:
>>def f(): return [ 0, 1 ]
....
>>f().append( 2 )
f()
[0, 1]

It constructs a new object each time. In light of this, the burden of
proof could even fall on Python for the inconsistency. That is,
assuming that it's well- and always defined.
Oct 12 '08 #16
On Oct 11, 4:41*am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
On Fri, 10 Oct 2008 06:20:35 -0700, bearophileHUGS wrote:
snip
I have seen professional programmers too use class attributes instead of
instance ones...

That's only a mistake if you don't mean to use class attributes instead
of instance attributes.
Off topic: That gives me an idea for an interesting technique.

class Foo( HasInstanceVars ):
class InstanceVars:
x= 0
y= None
z= [ 0, 1 ]

The __init__ method in HasInstanceVars adds any InstanceVars members
to the instance members. It's not terribly different than using
__init__-- slightly slower, slightly clearer. It could even include a
'__initvars__' variable which adds constructor parameters by name to
the instance. It's marginally problematic how to create new objects
each time Foo is instantiated. You could require factories, pickle-
unpickle the contents, require 'deepcopy' compatibility, execute a
string, or call a function which uniquely executes the class
statement.
>>foo= Foo()
foo.x+= 1
foo2= Foo()
foo2.x
0
>>foo.x
1

Oct 12 '08 #17
In article <48***********************@news.free.fr>,
Bruno Desthuilliers <br********************@websiteburo.invalid>
wrote:
David C. Ullrich a écrit :
In article
<5f**********************************@v53g2000hsa. googlegroups.com>,
kenneth <ke*****@inwind.itwrote:
On Oct 9, 10:14 am, Christian Heimes <li...@cheimes.dewrote:
kenneth wrote:
the 'd' variable already contains the 'self.d' value of the first
instance and not the default argument {}.
Am I doing some stupid error, or this is a problem ?
No, it always contains the default argument because default values are
created just ONE
TIME.http://effbot.org/pyfaq/why-are-defa...etween-objects
..
.

Wow, it's a very "dangerous" behavior ...

Just to know, is this written somewhere in the python documentation or
one has to discover it when his programs fails to work ;-) ?
At least once a week someone discovers this "problem", makes a
post about it here, and then someone points to the spot in the
documentation where it's explained.

Seems to me that people often site the "important warning" in
the tutorial. Of course there's no reason anyone would bother
going through the tutorial

Indeed. No reason at all.
- just for fun I looked in the
official Python Reference Manual to see whether they're explicit
about this or require the reader to figure it out from something
else they say.

There's a section titled "7.6 Function definitions". About halfway
through that section there's a _bold face_ statement
"Default parameter values are evaluated when the function definition is
executed.", followed by an explanation of how that can lead to
the sort of problem above.

But there's no reason to read the reference manual neither.
So I guess it _is_ awfully dangerous. They should really explain
this aspect of the language's behavior to people who don't read
the formal definition and also don't work through the tutorial.

You mean : "to people that don't bother reading the FineManual *nor*
searching the newsgroup / ML archives ?"
Yes. Also add "don't read any books". I think I started with some
book - the book pointed out the "surprise" you get when you say

L = [[0]] * 10
L[0][0] = 1

or something similar. I was probably surprised once by the
mutable default parameter thing once but having understood
that other example it wasn't hard to see what was happening.
Well... How to say.. Is there any chance these people will read anything
*at all* ?
No. That's exactly the point! Basic Python is so transparent that
you can start using it without reading anything, just looking at
a few examples. _Because_ of that it's their responsibility to
ensure that if you look at a few examples you then have a complete
understanding of the language.

In particular default parameters should work the way the user
expects! The fact that different users will expect different
things here is no excuse...

--
David C. Ullrich
Oct 14 '08 #18
On Oct 14, 1:50*pm, Bruno Desthuilliers
<bdesth.quelquech...@free.quelquepart.frwrote:
David C. Ullrich a écrit :
In article <48ef37fe$0$22798$426a3...@news.free.fr>,
*Bruno Desthuilliers <bruno.42.desthuilli...@websiteburo.invalid>
*wrote:
snip
(snip)
snip
In particular default parameters should work the way the user
expects! The fact that different users will expect different
things here is no excuse...

If different users expect different - mostly incompatible - things, how
would it be possible to have it working "the way the user expect" ?
Should Python grow some telepathic features to guess the user's
expectations and modifies itself to meet these expectations ?-)
No. Just have a user community that only has one user.
Oct 14 '08 #19
In message <01**********************@news.astraweb.com>, Steven D'Aprano
wrote:
On Thu, 09 Oct 2008 01:39:30 -0700, kenneth (a.k.a. Paolo) wrote:
>On Oct 9, 10:14Â*am, Christian Heimes <li...@cheimes.dewrote:
>>No, it always contains the default argument because default values are
created just ONE TIME
<http://effbot.org/pyfaq/why-are-default-values-shared-between-objects>...
>>

Wow, it's a very "dangerous" behavior ...

No, it's very *useful* behaviour.
Can you give an example of how useful it is? Something worth the pain of
newbies tripping over it every week?
Oct 16 '08 #20
Aaron "Castironpi" Brady wrote:
[about how default argument behavior should, in his opinion, be changed]

Say what you like. The language is as it is by choice. Were it, for some
reason, to change we would then be receiving posts every week that
didn't understand the *new* behavior.

Sometimes people just have to learn to confirm with reality instead of
requiring reality to confirm with their preconceptions. This is one such
case.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Oct 16 '08 #21
On Oct 15, 11:33*pm, Steve Holden <st...@holdenweb.comwrote:
Aaron "Castironpi" Brady wrote:

[about how default argument behavior should, in his opinion, be changed]

Say what you like. The language is as it is by choice. Were it, for some
reason, to change we would then be receiving posts every week that
didn't understand the *new* behavior.

Sometimes people just have to learn to confirm with reality instead of
requiring reality to confirm with their preconceptions. This is one such
case.

regards
*Steve
--
Steve Holden * * * *+1 571 484 6266 * +1 800 494 3119
Holden Web LLC * * * * * * *http://www.holdenweb.com/
I am not convinced it should either stay or go, but it's hard to argue
one way or the other about something so deeply entrenched. However,
what are your thoughts, whatever the default behavior is, on a
decorator that provides the alternative? That is, a decorator that
either reevaluates default arguments each time when the language
evaluates them once, or a decorator that evaluates arguments once,
when the languages evaluates them each time?

P.S.
we would then be receiving posts every week that
didn't understand the *new* behavior.
That is not obvious and I don't know of any empirical evidence that
entails it. Hard to search the standard library for that figure.
Oct 16 '08 #22
On Wed, Oct 15, 2008 at 9:43 PM, Aaron Castironpi Brady
<ca********@gmail.comwrote:
On Oct 15, 11:33 pm, Steve Holden <st...@holdenweb.comwrote:
>Aaron "Castironpi" Brady wrote:

[about how default argument behavior should, in his opinion, be changed]

Say what you like. The language is as it is by choice. Were it, for some
reason, to change we would then be receiving posts every week that
didn't understand the *new* behavior.

Sometimes people just have to learn to confirm with reality instead of
requiring reality to confirm with their preconceptions. This is one such
case.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

I am not convinced it should either stay or go, but it's hard to argue
one way or the other about something so deeply entrenched. However,
what are your thoughts, whatever the default behavior is, on a
decorator that provides the alternative? That is, a decorator that
either reevaluates default arguments each time when the language
evaluates them once, or a decorator that evaluates arguments once,
when the languages evaluates them each time?

P.S.
>we would then be receiving posts every week that
didn't understand the *new* behavior.
That is not obvious and I don't know of any empirical evidence that
entails it. Hard to search the standard library for that figure.
Although primitive and likely somewhat flawed, you may find the
statistics in the "Compatibility Issues" section of
http://mail.python.org/pipermail/pyt...ry/005704.html
to be of interest.

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
--
http://mail.python.org/mailman/listinfo/python-list
Oct 16 '08 #23
Chris Rebert:
Although primitive and likely somewhat flawed, you may find the
statistics in the "Compatibility Issues" section ofhttp://mail.python.org/pipermail/python-3000/2007-February/005704.html
to be of interest.
I am quite glad to see that I am not the only one that cares for such
topic. And I think Guido is wrong here, but I can also see there's
little hope in fixing this Python wart. We'll probably have to see and
use another language to see this problem/bug fixed in some way (and
maybe other issues added, no language is perfect). Python is now
mature, being 15+ years old, so it's also rigid. Computer languages,
just like living species, resist change, and usually you need a new
language/species to fix some larger warts/bugs/design problems.
Python3 fixes tons of problems of Python2.x, but it's almost a new
language :-)

Bye,
bearophile
Oct 16 '08 #24
On Thu, 16 Oct 2008 17:05:40 +1300, Lawrence D'Oliveiro wrote:
In message <01**********************@news.astraweb.com>, Steven D'Aprano
wrote:
>On Thu, 09 Oct 2008 01:39:30 -0700, kenneth (a.k.a. Paolo) wrote:
>>On Oct 9, 10:14Â*am, Christian Heimes <li...@cheimes.dewrote:

No, it always contains the default argument because default values
are created just ONE TIME
<http://effbot.org/pyfaq/why-are-defa...hared-between-
objects>...
>>>

Wow, it's a very "dangerous" behavior ...

No, it's very *useful* behaviour.

Can you give an example of how useful it is? Something worth the pain of
newbies tripping over it every week?

Did you read the effbot's explanation in the link above? He gives two
examples, memoization and binding of locals.

The second example is especially interesting, because that's also a
Gotcha for newbies (not just noobs either...), and the solution to that
specific gotcha is Python's use of define-time binding of default values.

>>callbacks = [None]*4
for i in xrange(len(callbacks)):
.... callbacks[i] = lambda s: '%d %s' % (i, s)
....
>>for cb in callbacks:
.... print cb('string')
....
3 string
3 string
3 string
3 string
Newbies get confused by this almost as often as by the default value
semantics, but the simplest solution to this gotcha is to use Python's
default values:
>>for i in xrange(len(callbacks)):
.... callbacks[i] = lambda s, i=i: '%d %s' % (i, s)
....
>>for cb in callbacks:
.... print cb('string')
....
0 string
1 string
2 string
3 string
If Python re-evaluated the default value i=i at runtime, the above would
break.

--
Steven
Oct 16 '08 #25
On Oct 16, 1:05*am, "Chris Rebert" <c...@rebertia.comwrote:
On Wed, Oct 15, 2008 at 9:43 PM, Aaron Castironpi Brady

<castiro...@gmail.comwrote:
On Oct 15, 11:33 pm, Steve Holden <st...@holdenweb.comwrote:
Aaron "Castironpi" Brady wrote:
[about how default argument behavior should, in his opinion, be changed]
Say what you like. The language is as it is by choice. Were it, for some
reason, to change we would then be receiving posts every week that
didn't understand the *new* behavior.
Sometimes people just have to learn to confirm with reality instead of
requiring reality to confirm with their preconceptions. This is one such
case.
regards
*Steve
--
Steve Holden * * * *+1 571 484 6266 * +1 800 494 3119
Holden Web LLC * * * * * * *http://www.holdenweb.com/
I am not convinced it should either stay or go, but it's hard to argue
one way or the other about something so deeply entrenched. *However,
what are your thoughts, whatever the default behavior is, on a
decorator that provides the alternative? *That is, a decorator that
either reevaluates default arguments each time when the language
evaluates them once, or a decorator that evaluates arguments once,
when the languages evaluates them each time?
P.S.
we would then be receiving posts every week that
didn't understand the *new* behavior.
That is not obvious and I don't know of any empirical evidence that
entails it. *Hard to search the standard library for that figure.

Although primitive and likely somewhat flawed, you may find the
statistics in the "Compatibility Issues" section ofhttp://mail.python.org/pipermail/python-3000/2007-February/005704.html
to be of interest.

Cheers,
Chris
--
Follow the path of the Iguana...http://rebertia.com
--
http://mail.python.org/mailman/listinfo/python-list

I remember, I've seen it before. Are you proposing that the number of
posts we'd receive about this feature is proportional to its frequency
of usage?
Oct 16 '08 #26
On Oct 16, 12:23*pm, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
On Thu, 16 Oct 2008 17:05:40 +1300, Lawrence D'Oliveiro wrote:
In message <01006451$0$20646$c3e8...@news.astraweb.com>, Steven D'Aprano
wrote:
On Thu, 09 Oct 2008 01:39:30 -0700, kenneth (a.k.a. Paolo) wrote:
>On Oct 9, 10:14*am, Christian Heimes <li...@cheimes.dewrote:
>>No, it always contains the default argument because default values
are created just ONE TIME
<http://effbot.org/pyfaq/why-are-defa...hared-between-
objects>...
>Wow, it's a very "dangerous" behavior ...
No, it's very *useful* behaviour.
Can you give an example of how useful it is? Something worth the pain of
newbies tripping over it every week?

Did you read the effbot's explanation in the link above? He gives two
examples, memoization and binding of locals.

The second example is especially interesting, because that's also a
Gotcha for newbies (not just noobs either...), and the solution to that
specific gotcha is Python's use of define-time binding of default values.
snip
Newbies get confused by this almost as often as by the default value
semantics, but the simplest solution to this gotcha is to use Python's
default values:
snip

Both of those are shorthand notations and there are alternative ways
to express both of them. The alternatives might even be more literal,
that is, less idiomatic, in the language's tokens' semantics.

For the first one, effbot says: 'You could use a global variable
containing a dictionary instead of the default value; it’s a matter of
taste'. You could also use an attribute of the function, which is an
entry in func_dict.

For the second one, it is more verbose, but you can add an enclosing
lambda or def expression, and call it on the spot. I'll be honest:
those are plusses, that is pros of the decision, but they aren't that
strong.
If Python re-evaluated the default value i=i at runtime, the above would
break.
Not with a mere extra lambda. The fact that a syntax is an
opportunity to have a behavior does not imply that it should have
one. The fact that newbies ask about these semantics doesn't imply
that they'd ask about another one just as much. The fact that these
semantics have these two uses, doesn't imply that the others don't
have more. Immutable defaults behave identically in both.
--
Steven
Oct 16 '08 #27
In article <48***********************@news.free.fr>,
Bruno Desthuilliers <bd*****************@free.quelquepart.frwrote:
David C. Ullrich a écrit :
In article <48***********************@news.free.fr>,
Bruno Desthuilliers <br********************@websiteburo.invalid>
wrote:
David C. Ullrich a écrit :
(snip)
>Seems to me that people often site the "important warning" in
the tutorial. Of course there's no reason anyone would bother
going through the tutorial
Indeed. No reason at all.

- just for fun I looked in the
official Python Reference Manual to see whether they're explicit
about this or require the reader to figure it out from something
else they say.

There's a section titled "7.6 Function definitions". About halfway
through that section there's a _bold face_ statement
"Default parameter values are evaluated when the function definition is
executed.", followed by an explanation of how that can lead to
the sort of problem above.
But there's no reason to read the reference manual neither.

So I guess it _is_ awfully dangerous. They

Hum... Who are "they", exactly ?
>should really explain
this aspect of the language's behavior to people who don't read
the formal definition and also don't work through the tutorial.
You mean : "to people that don't bother reading the FineManual *nor*
searching the newsgroup / ML archives ?"
Yes. Also add "don't read any books".

Indeed.
I think I started with some
book

As far as I'm concerned, I started with the FineManual(tm)'s tutorial.

(snip)
Well... How to say.. Is there any chance these people will read anything
*at all* ?
No. That's exactly the point!

Yeps. But I don't think we derive the same conclusions from that point.
Erm, I think maybe your irony detector needs a little calibration...
[...]
In particular default parameters should work the way the user
expects! The fact that different users will expect different
things here is no excuse...
I was worried someone might not realize I was being sarcastic,
which is why I threw in this obvious impossibility
If different users expect different - mostly incompatible - things, how
would it be possible to have it working "the way the user expect" ?
but I guess it wasn't enough.
Should Python grow some telepathic features to guess the user's
expectations and modifies itself to meet these expectations ?-)
--
David C. Ullrich
Oct 16 '08 #28
On Thu, 16 Oct 2008 12:18:49 -0700, Aaron \"Castironpi\" Brady wrote:

[snip]
>If Python re-evaluated the default value i=i at runtime, the above
would break.

Not with a mere extra lambda.
Not so. It has nothing to do with lambda, lambda just happens to be a
convenient example. Here's the code I demonstrated:
>>for i in xrange(len(callbacks)):
.... callbacks[i] = lambda s, i=i: '%d %s' % (i, s)
....
>>for cb in callbacks:
.... print cb('string')
....
0 string
1 string
2 string
3 string
At the end of the first loop, i == 3. If the default value i=i was re-
evaluated each time the function was called, then i would get the value 3
each time, which is the same behaviour you get from the version with this:

callbacks[i] = lambda s: '%d %s' % (i, s)

Worse, because you're now relying on i as a global, it's subject to
strange and mysterious bugs if you later change i and then call the
callback.
The fact that a syntax is an opportunity
to have a behavior does not imply that it should have one. The fact
that newbies ask about these semantics doesn't imply that they'd ask
about another one just as much. The fact that these semantics have
these two uses, doesn't imply that the others don't have more.
Nowhere did I say that the one logically implies the other. I was asked
for examples of how the current behaviour is useful, not to prove that
the current behaviour logically follows from first principles. If you
want to use a programming language where function default values are re-
evaluated at runtime, you know where to find them.

By the way, for the record I myself has found that behaviour useful on
occasion. But that's easy to do with current Python:
def spam(x, y=None):
if y is None:
# re-evaluate the default value at runtime
y = get_some_other_value()
return x + y

So if you want that behaviour, you can get it. But if Python's semantics
changed, then how would you implement today's semantics where the default
is evaluated once only? I don't think you can. So Python's current
semantics allows the behaviour you want, but in a slightly inconvenient
form; but the re-evaluate-at-runtime semantics would prevent the
behaviour I want completely.
Immutable defaults behave identically in both.
Not quite. To have immutable defaults behave identically, you would need
to remove at least one more feature of Python: the ability to set a
default value to an arbitrary expression, not just a literal.

Why do you need to do this? This toy example demonstrates the problem if
you don't:

yy = 3 # immutable value bound to the name yy
def spam(x, y=yy-1):
return x + y
will have the *expression* yy-1 re-evaluated when they call the function.
That means that even though 2 is immutable, you can no longer rely on the
default value being 2, or even existing at all. (What if I del yy at some
point, then call the function?)

So now to get the behaviour you desire, you not only have to change the
way Python functions are implemented (and that will have a real and
significant performance cost), but you also have to change the parser to
only allow literals as default values.

Note that there is absolutely nothing wrong with using an expression when
setting default values. But you have to prohibit it, or else introduce
unexpected behaviour which will trip up not just noobs but everybody. And
then you'll have noobs writing in weekly asking why they can't write
"def foo(x, y=10**6)" instead of y=10000000.

--
Steven
Oct 17 '08 #29
On Oct 16, 7:54*pm, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
On Thu, 16 Oct 2008 12:18:49 -0700, Aaron \"Castironpi\" Brady wrote:

[snip]
If Python re-evaluated the default value i=i at runtime, the above
would break.
Not with a mere extra lambda.

Not so. It has nothing to do with lambda, lambda just happens to be a
convenient example. Here's the code I demonstrated:
>for i in xrange(len(callbacks)):

... * * callbacks[i] = lambda s, i=i: '%d %s' % (i, s)
...>>for cb in callbacks:

... * * print cb('string')
...
0 string
1 string
2 string
3 string

At the end of the first loop, i == 3. If the default value i=i was re-
evaluated each time the function was called, then i would get the value 3
each time, which is the same behaviour you get from the version with this:

callbacks[i] = lambda s: '%d %s' % (i, s)

Worse, because you're now relying on i as a global, it's subject to
strange and mysterious bugs if you later change i and then call the
callback.
The fact that a syntax is an opportunity
to have a behavior does not imply that it should have one. *The fact
that newbies ask about these semantics doesn't imply that they'd ask
about another one just as much. *The fact that these semantics have
these two uses, doesn't imply that the others don't have more.

Nowhere did I say that the one logically implies the other. I was asked
for examples of how the current behaviour is useful, not to prove that
the current behaviour logically follows from first principles. If you
want to use a programming language where function default values are re-
evaluated at runtime, you know where to find them.

By the way, for the record I myself has found that behaviour useful on
occasion. But that's easy to do with current Python:

def spam(x, y=None):
* * if y is None:
* * * * # re-evaluate the default value at runtime
* * * * y = get_some_other_value()
* * return x + y

So if you want that behaviour, you can get it. But if Python's semantics
changed, then how would you implement today's semantics where the default
is evaluated once only? I don't think you can. So Python's current
semantics allows the behaviour you want, but in a slightly inconvenient
form; but the re-evaluate-at-runtime semantics would prevent the
behaviour I want completely.
Immutable defaults behave identically in both.

Not quite. To have immutable defaults behave identically, you would need
to remove at least one more feature of Python: the ability to set a
default value to an arbitrary expression, not just a literal.

Why do you need to do this? This toy example demonstrates the problem if
you don't:

yy = 3 *# immutable value bound to the name yy
def spam(x, y=yy-1):
* * return x + y

will have the *expression* yy-1 re-evaluated when they call the function.
That means that even though 2 is immutable, you can no longer rely on the
default value being 2, or even existing at all. (What if I del yy at some
point, then call the function?)

So now to get the behaviour you desire, you not only have to change the
way Python functions are implemented (and that will have a real and
significant performance cost), but you also have to change the parser to
only allow literals as default values.

Note that there is absolutely nothing wrong with using an expression when
setting default values. But you have to prohibit it, or else introduce
unexpected behaviour which will trip up not just noobs but everybody. And
then you'll have noobs writing in weekly asking why they can't write
"def foo(x, y=10**6)" instead of y=10000000.

--
Steven
You're correct. I overstated the fact.
Immutable defaults behave identically in both.
Not quite. To have immutable defaults behave identically, you would need
Immutable literal defaults behave identically in both. Obviously
semantics would change if semantics change.
Not with a mere extra lambda.

Not so. It has nothing to do with lambda, lambda just happens to be a
convenient example. Here's the code I demonstrated:
snip

What I stated is true, but I may not have stated it verbosely enough.
>>callbacks= [ None ]* 3
for i in range( len( callbacks ) ):
.... callbacks[ i ]= ( lambda i: ( lambda s: '%d %s' % (i, s) ) )
( i )
....
>>for cb in callbacks:
.... print cb('string')
....
0 string
1 string
2 string

One extra lambda, called on the spot, as I stated. The 'callbacks'
items do not rely on 'i' as a global; they contain a cell that refers
to the contents of 'i' at the time they're called, that is, a entry in
unique namespaces. When 'i' is rebound the next time through the loop
or later, or deleted, they still have their values of it.

Of course, if you're iterating over a collection of mutables, the
namespaces get references to those. Then, if you mutate your iterator
variable later, as opposed to rebind it, the namespace which contains
it in a cell will see that change; they are one in the same object.
Yours does that too.
Nowhere did I say that the one logically implies the other. I was asked
for examples of how the current behaviour is useful, not to prove that
the current behaviour logically follows from first principles. If you
want to use a programming language where function default values are re-
evaluated at runtime, you know where to find them.
I'm almost getting the feeling that you're being defensive/protective
of Python of one of its quirks, as though that was important to its
identity, and you just couldn't look on it the same without it. (A
pop t.v. character exclaimed, "I can't believe you caved!") I'm not
sure to what extent pride factors in to stubbornness like that. Is it
a selection criteria, such as you have to like quirks to be friends
with Pythoners? No offense or anything; we're all proud of Python.

With, adopting the term, 'per-call evaluations', expressions
participate at their own risk. If they refer to a variable that isn't
in their namespace closure, the evaulation of them fails. It's true
whether you do it by hand:

def f( a= None ):
if a is None:
a= i #i non-local

Or it occurs in the language's definition.
... not to prove that
the current behaviour logically follows from first principles.
Well, does it? I jest. It's not clear either one does.

Incidentally, you could combine the two issues to get a persistent
reference to the non-local variable you want to use in a default
value, copying it into the namespace; but you just have to mutate it
via its location when you do.

I think a decorator would be a good compromise. Python keeps its
definition-time evaluation, and newbies, or whoever needs them, are
still able to use per-call evaluation.
yy = 3 # immutable value bound to the name yy
def spam(x, y=yy-1):
return x + y
yy= 3
@calltime_default( y= yy- 1 ) #might need quotes
def spam(x, y):
return x + y

Then if you delete yy, 'spam' fails correctly. I don't really see an
argument that it hurts the language (or the standard library) any...
provided its possible without syntax support.

I'm not so sure that weeding out newcomers by inattentiveness isn't
unconstructive or unbeneficial to either group, vets or newcomers.
You might argue that the same individuals would just ask just as
inattentive questions later on... but at least vets would have some
variety, and Python would have more fans. It's not clear that the
feature is doing them the favor of gauging for them the level of
attentiveness writing Python requires. I'll point out though as an
aside, that harmless introversion can be mistaken for actual elitism.
Oct 17 '08 #30
In message <Xn*************************@127.0.0.1>, Duncan Booth wrote:
We already get people asking why code like this doesn't return 3:
>>>fns = [ lambda: x for x in range(10) ]
fns[3]()
9

... making this change to default arguments would mean the
solution usually proposed to the function scoping question above would no
longer work:
>>>fns = [ lambda y=x: y for x in range(10) ]
fns[3]()
3
The right solution, of course, is

fns = [(lambda x : lambda : x)(x) for x in range(10)]

Oct 17 '08 #31
On Fri, 17 Oct 2008 23:04:52 +1300, Lawrence D'Oliveiro wrote:
In message <Xn*************************@127.0.0.1>, Duncan Booth wrote:
>We already get people asking why code like this doesn't return 3:
>>>>fns = [ lambda: x for x in range(10) ] fns[3]()
9

... making this change to default arguments would mean the solution
usually proposed to the function scoping question above would no longer
work:
>>>>fns = [ lambda y=x: y for x in range(10) ] fns[3]()
3

The right solution, of course, is

fns = [(lambda x : lambda : x)(x) for x in range(10)]


Only if by "right solution" you mean "excessively verbose, confusing, and
the sort of thing that makes even supporters of lambda cringe".

Yes yes, it's just a factory function written with lambdas. It's still
ugly and exactly the sort of thing that gives ammunition to lambda-
haters. Unlike the solution given by Duncan, which is understandable to
any newbie who has learned about default values and lambda, your solution
requires an understanding of higher-level functions (functions that
return functions, for anyone who doesn't recognise the term) that most
newbies won't have.

And while I don't much care for premature optimization, I will point out
that creating a factory function just to call it once then throw it away
is very wasteful, and that waste is demonstrated by the running time
being more than double that of Duncan's solution:

>>timeit.Timer('[ lambda y=x: y for x in range(10) ]').repeat()
[7.6332600116729736, 6.9825620651245117, 7.0891578197479248]
>>timeit.Timer('[(lambda x : lambda : x)(x) for x in range(10)]').repeat()
[18.984915971755981, 17.808281898498535, 18.432481050491333]


--
Steven
Oct 17 '08 #32
On Oct 17, 6:56*am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
On Fri, 17 Oct 2008 23:04:52 +1300, Lawrence D'Oliveiro wrote:
In message <Xns9B33BC4CC1480duncanbo...@127.0.0.1>, Duncan Booth wrote:
We already get people asking why code like this doesn't return 3:
>>>fns = [ lambda: x for x in range(10) ] fns[3]()
9
... making this change to default arguments would mean the solution
usually proposed to the function scoping question above would no longer
work:
>>>fns = [ lambda y=x: y for x in range(10) ] fns[3]()
3
The right solution, of course, is
* * fns = [(lambda x : lambda : x)(x) for x in range(10)]

Only if by "right solution" you mean "excessively verbose, confusing, and
the sort of thing that makes even supporters of lambda cringe".

Yes yes, it's just a factory function written with lambdas. It's still
ugly and exactly the sort of thing that gives ammunition to lambda-
haters. Unlike the solution given by Duncan, which is understandable to
any newbie who has learned about default values and lambda, your solution
requires an understanding of higher-level functions (functions that
return functions, for anyone who doesn't recognise the term) that most
newbies won't have.

And while I don't much care for premature optimization, I will point out
that creating a factory function just to call it once then throw it away
is very wasteful, and that waste is demonstrated by the running time
being more than double that of Duncan's solution:
>timeit.Timer('[ lambda y=x: y for x in range(10) ]').repeat()

[7.6332600116729736, 6.9825620651245117, 7.0891578197479248]>>timeit.Timer('[(lambda x : lambda : x)(x) for x in range(10)]').repeat()

[18.984915971755981, 17.808281898498535, 18.432481050491333]

--
Steven
No, there's a difference in meaning. One creates a function that is
called with 0 arguments. The other creates a function that can be
called with 0 or 1 arguments. The purpose of a parameter is something
that the caller can supply, but doesn't have to. It is not for
internal-use-only items. Nested namespaces and object attributes can
be.
Oct 17 '08 #33
In message
<da**********************************@k30g2000hse. googlegroups.com>,
Aaron "Castironpi" Brady wrote:
The purpose of a parameter is something that the caller can supply, but
doesn't have to. It is not for internal-use-only items.
Exactly!
Oct 17 '08 #34
In message <01**********************@news.astraweb.com>, Steven D'Aprano
wrote:
On Fri, 17 Oct 2008 23:04:52 +1300, Lawrence D'Oliveiro wrote:
>The right solution, of course, is

fns = [(lambda x : lambda : x)(x) for x in range(10)]

Only if by "right solution" you mean "excessively verbose, confusing, and
the sort of thing that makes even supporters of lambda cringe".

Yes yes, it's just a factory function written with lambdas. It's still
ugly and exactly the sort of thing that gives ammunition to lambda-
haters.
It's NOT ugly. It's EXACTLY the right sort of thing you do with
lambda-expressions, going right back to Church.

It's no more ugly than, say, parentheses in Lisp. :)
Oct 17 '08 #35
On Sat, 18 Oct 2008 09:17:28 +1300, Lawrence D'Oliveiro wrote:
In message
<da**********************************@k30g2000hse. googlegroups.com>,
Aaron "Castironpi" Brady wrote:
>The purpose of a parameter is something that the caller can supply, but
doesn't have to. It is not for internal-use-only items.

Exactly!
Says who?

Using arguments for internal-use-only is a perfectly acceptable example
of practicality beating purity.


--
Steven
Oct 19 '08 #36
Steven D'Aprano wrote:
On Sat, 18 Oct 2008 09:17:28 +1300, Lawrence D'Oliveiro wrote:
>In message
<da**********************************@k30g2000hse .googlegroups.com>,
Aaron "Castironpi" Brady wrote:
>>The purpose of a parameter is something that the caller can supply, but
doesn't have to. It is not for internal-use-only items.

Exactly!

Says who?

Using arguments for internal-use-only is a perfectly acceptable example
of practicality beating purity.
That's a stretch.
Oct 19 '08 #37
On Sun, 19 Oct 2008 02:52:52 +0000, Aaron Brady wrote:
Steven D'Aprano wrote:
>On Sat, 18 Oct 2008 09:17:28 +1300, Lawrence D'Oliveiro wrote:
>>In message
<da**********************************@k30g2000hs e.googlegroups.com>,
Aaron "Castironpi" Brady wrote:

The purpose of a parameter is something that the caller can supply,
but doesn't have to. It is not for internal-use-only items.

Exactly!

Says who?

Using arguments for internal-use-only is a perfectly acceptable example
of practicality beating purity.

That's a stretch.

It's a standard Python idiom used by the standard library.

--
Steven
Oct 19 '08 #38
Steven D'Aprano wrote:
On Sun, 19 Oct 2008 02:52:52 +0000, Aaron Brady wrote:
>Steven D'Aprano wrote:
>>On Sat, 18 Oct 2008 09:17:28 +1300, Lawrence D'Oliveiro wrote:

In message
<da**********************************@k30g2000h se.googlegroups.com>,
Aaron "Castironpi" Brady wrote:

The purpose of a parameter is something that the caller can supply,
but doesn't have to. It is not for internal-use-only items.

Exactly!

Says who?

Using arguments for internal-use-only is a perfectly acceptable example
of practicality beating purity.

That's a stretch.


It's a standard Python idiom used by the standard library.
It's a compromise solution, where the other compromises are about as
good.

....Except for the confused newbies. But why should they pick this
feature to ignore the documentation for? It trades off intuitiveness
for convenience.

Oct 19 '08 #39
On Oct 14, 1:36*pm, "David C. Ullrich" <dullr...@sprynet.comwrote:
Well... How to say.. Is there any chance these people will read anything
*at all* ?

No. That's exactly the point! Basic Python is so transparent that
you can start using it without reading anything, just looking at
a few examples. _Because_ of that it's their responsibility to
ensure that if you look at a few examples you then have a complete
understanding of the language.
I agree, Python really does strive to be intuitive and easy-to-learn.
So the oddity of the behavior of "optional_list_arg=[]" is a recurring
surprise to those who jump first and read documentation later.
Besides the tutorials, reference docs, and FAQs, there are also some
web pages with titles like "Python Gotchas" and "Common Mistakes in
Python" that usually tread this ground too.
In particular default parameters should work the way the user
expects! The fact that different users will expect different
things here is no excuse...
Are you being sarcastic? Short of "import mindreading", I don't know
how Python would know which behavior a given user would expect. Maybe
instead of a "code smell", this particular Python wart is a "design
smell".

What is surprising is that Python cannot discriminate between this:
y = 100
def f(a,x=y):
print a+x
>>f(1)
101
>>y=200
f(1)
101

and this:

def f(a,x=[]):
print a+len(x)
x.append(a)
>>f(1)
1
>>f(1)
2
>>f(1,[1,2,3])
4
>>>
Is x supposed to be a default arg or a "static" arg (in the sense of a
static var within a function as one finds in C)?

-- Paul
Oct 19 '08 #40
On Sun, Oct 19, 2008 at 12:56 AM, Paul McGuire <pt***@austin.rr.comwrote:
On Oct 14, 1:36 pm, "David C. Ullrich" <dullr...@sprynet.comwrote:
Well... How to say.. Is there any chance these people will read anything
*at all* ?

No. That's exactly the point! Basic Python is so transparent that
you can start using it without reading anything, just looking at
a few examples. _Because_ of that it's their responsibility to
ensure that if you look at a few examples you then have a complete
understanding of the language.
I agree, Python really does strive to be intuitive and easy-to-learn.
So the oddity of the behavior of "optional_list_arg=[]" is a recurring
surprise to those who jump first and read documentation later.
Besides the tutorials, reference docs, and FAQs, there are also some
web pages with titles like "Python Gotchas" and "Common Mistakes in
Python" that usually tread this ground too.
Specifically:
http://www.onlamp.com/pub/a/python/2...on.html?page=2
http://www.ferg.org/projects/python_...ontents_item_6
http://zephyrfalcon.org/labs/python_pitfalls.html

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
>
>In particular default parameters should work the way the user
expects! The fact that different users will expect different
things here is no excuse...
Are you being sarcastic? Short of "import mindreading", I don't know
how Python would know which behavior a given user would expect. Maybe
instead of a "code smell", this particular Python wart is a "design
smell".

What is surprising is that Python cannot discriminate between this:
y = 100
def f(a,x=y):
print a+x
>>>f(1)
101
>>>y=200
f(1)
101

and this:

def f(a,x=[]):
print a+len(x)
x.append(a)
>>>f(1)
1
>>>f(1)
2
>>>f(1,[1,2,3])
4
>>>>

Is x supposed to be a default arg or a "static" arg (in the sense of a
static var within a function as one finds in C)?

-- Paul
--
http://mail.python.org/mailman/listinfo/python-list
Oct 19 '08 #41
On Sun, 19 Oct 2008 00:56:17 -0700, Paul McGuire wrote:
On Oct 14, 1:36Â*pm, "David C. Ullrich" <dullr...@sprynet.comwrote:
....
>In particular default parameters should work the way the user expects!
The fact that different users will expect different things here is no
excuse...
Are you being sarcastic?
Yes, David was being sarcastic. Or possibly ironic. Satirical? One of
those humour things. Whatever it was, I think you're the second person
who missed it.

Short of "import mindreading", I don't know
how Python would know which behavior a given user would expect.
Exactly.

Besides, Guido has a time machine, and apparently antigravity is being
added to the standard library, so I don't see why we can't have
mindreading too.


--
Steven
Oct 19 '08 #42
David C. Ullrich a écrit :
In article <48***********************@news.free.fr>,
Bruno Desthuilliers <bd*****************@free.quelquepart.frwrote:
(snip)
>>>Well... How to say.. Is there any chance these people will read anything
*at all* ?
No. That's exactly the point!
Yeps. But I don't think we derive the same conclusions from that point.

Erm, I think maybe your irony detector needs a little calibration...
Possibly, yes...
>>[...]
In particular default parameters should work the way the user
expects! The fact that different users will expect different
things here is no excuse...

I was worried someone might not realize I was being sarcastic,
which is why I threw in this obvious impossibility
>If different users expect different - mostly incompatible - things, how
would it be possible to have it working "the way the user expect" ?

but I guess it wasn't enough.
Obviously not - at least for me. OTHO, I've seen peoples very seriously
asking for such obvious impossibilities.
>Should Python grow some telepathic features to guess the user's
expectations and modifies itself to meet these expectations ?-)
And the answer is, of course, 42.

Oct 20 '08 #43
In article
<25**********************************@v72g2000hsv. googlegroups.com>,
Paul McGuire <pt***@austin.rr.comwrote:
On Oct 14, 1:36*pm, "David C. Ullrich" <dullr...@sprynet.comwrote:
>[...]
In particular default parameters should work the way the user
expects! The fact that different users will expect different
things here is no excuse...
Are you being sarcastic?
Why would you think that? Seems like a perfectly reasonable
request.
Short of "import mindreading", I don't know
how Python would know which behavior a given user would expect.
I guess that's why I'm not a programmer - not able to think
this sort of thing through properly. Thanks. This explains
a lot of other things I've wondered about for years, like
why I need to tell the waitress whether I want tea or coffee,
why I sometimes need to switch channels on my TV... that's
always been what I like about c.l.py, getting answers to
questions I haven't even asked.

--
David C. Ullrich
Oct 21 '08 #44

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Miki Tebeka | last post by:
Hello All, I have a frame that contains a panel and several buttons. I'd like to make one of the button the default button but self.SetDefaultItem(btn) or btn.SetFocus() don't work. The item in...
26
by: Alex Panayotopoulos | last post by:
Hello all, Maybe I'm being foolish, but I just don't understand why the following code behaves as it does: - = - = - = - class listHolder: def __init__( self, myList= ): self.myList =...
2
by: Gabriel Genellina | last post by:
Hi In the following code sample, I have: - a Worker class, which could have a lot of methods and attributes. In particular, it has a 'bar' attribute. This class can be modified as needed. - a...
49
by: Mark Hahn | last post by:
As we are addressing the "warts" in Python to be fixed in Prothon, we have come upon the mutable default parameter problem. For those unfamiliar with the problem, it can be seen in this Prothon...
14
by: ago | last post by:
Is it possible to have a default value associated python objects? I.e. to flag an attribute in such a way that the assignment operator for the object returns the default attribute instead of the...
5
by: netvaibhav | last post by:
Hi All: Here's a piece of Python code and it's output. The output that Python shows is not as per my expectation. Hope someone can explain to me this behaviour: class MyClass: def...
44
by: gregory.petrosyan | last post by:
Hello everybody! I have little problem: class A: def __init__(self, n): self.data = n def f(self, x = ????) print x All I want is to make self.data the default argument for self.f(). (I
10
by: Alan G Isaac | last post by:
My class MyClass reuses many default parameters with a small number of changes in each instance. For various reasons I decided to put all the parameters in a separate Params class, instances of...
7
by: George Sakkis | last post by:
A situation that often comes up is having to initialize several instance attributes that accept a default value. For a single class, passing the default values in __init__ is fine: class...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.