By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,965 Members | 1,631 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,965 IT Pros & Developers. It's quick & easy.

Optional parameter object re-used when instantiating multiple objects

P: n/a
Hello All,

Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.

class Blob:
def __init__(self, points=[]):
self._points = points
b = Blob()
c = Blob()

b._points.append(1)
c._points.append(2)

print b._points

# this will show that b._points is the same object as c._points



Nov 15 '08 #1
Share this Question
Share on Google+
35 Replies


P: n/a
Rick Giuly <rg**********@yahoo.comwrites:
Hello All,
Hello,
Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.

class Blob:
def __init__(self, points=[]):
self._points = points
b = Blob()
c = Blob()

b._points.append(1)
c._points.append(2)

print b._points

# this will show that b._points is the same object as c._points
This is probably the MFAQ (Most FAQ)!

Have a look in http://www.python.org/doc/faq/ (I can't point at the
question as my internet pipes to the US are very rusty this morning)

HTH

--
Arnaud
Nov 15 '08 #2

P: n/a
On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
Hello All,

Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.
That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different list
each time, you should have said so. Don't blame the language for doing
exactly what you told it to do.

class Blob:
def __init__(self, points=[]):
self._points = points
Let's analyze this. You create a method __init__. That function is
created *once*. As part of the process of creating the function, the
argument "points" is given the default value of an empty list. The
creation of that empty list happens *once*, when the method is created.
In the body of the function, you set the _points attribute to points.
Naturally it is the same list object.

Since the method is only created once, it is only natural that the
default value is also only created once. If you want something to be
created each time the function is called, you have to put it inside the
body of the function:

class Blob:
def __init__(self, points=None):
if points is None:
points = []
self._points = points

Now you will have _points set to a unique empty list each time.

This is no different from doing this:

alist = []
b1 = Blob(alist)
b2 = Blob(alist)

Would you be surprised that b1 and b2 share the same list? If yes, then
you need to think about how Python really works, rather than how you
imagine it works.

--
Steven
Nov 16 '08 #3

P: n/a
On Nov 15, 3:40*am, Rick Giuly <rgiuly.gr...@yahoo.comwrote:
Hello All,

Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.

class Blob:
* * def __init__(self, points=[]):
* * * * self._points = points

b = Blob()
c = Blob()

b._points.append(1)
c._points.append(2)

print b._points

# this will show that b._points is the same object as c._points
Hi Rick,

I don't think Dennis or Steven read your post very well. You said
'Why does Python do X?', and 'It seems natural to you to do not X'.
Dennis and Steven both said, 'Python does X'.

Steven did get around to suggesting an answer though. He said:
If you want something to be
created each time the function is called, you have to put it inside the
body of the function:
Taking this to be true, the answer to your question is, 'Because the
object isn't created inside the body of the function,' or, 'Because
the argument list is outside the body of the function'.

From your post, it's hard to tell whether this 'duh'-type observation
would point out the salient feature of the construct, or whether
you're after something deeper.

If you're asking, 'Why isn't the argument list considered to be inside
the body?', then the answer is, it's pretty much arbitrary.
Regardless of which one the author of Python chose, the other's
workaround would be equally short, and neither one is obviously
indicated by the syntax.

And until someone sends you a link to Python's author's blog that
gives the answer, 'To make creating static variables really easy',
don't let them tell you so.
Nov 16 '08 #4

P: n/a
On Sat, 15 Nov 2008 21:29:22 -0800, Aaron Brady wrote:
I don't think Dennis or Steven read your post very well.
It's possible.
You said 'Why
does Python do X?', and 'It seems natural to you to do not X'. Dennis
and Steven both said, 'Python does X'.
I also disputed that it is natural to do not-X (runtime creation of
default arguments), and explained why such an interpretation doesn't
match with the way Python operates. I admit I didn't answer the "why"
part.

Steven did get around to suggesting an answer though. He said:
>If you want something to be
created each time the function is called, you have to put it inside the
body of the function:
If you want to be pedantic, then my "answer" (which you seem to approve
of) doesn't correspond to either of the original poster's questions. If
you're going to be pedantic, then be pedantic all the way, and criticize
me for answering a question that wasn't asked :-P

Taking this to be true, the answer to your question is, 'Because the
object isn't created inside the body of the function,' or, 'Because the
argument list is outside the body of the function'.
Actually, the correct answer to "Why?" would be "Because that's the
decision Guido van Rossum made back in the early 1990s when he first
started designing Python". That of course leads to the obvious question
"Why did he make that decision?", and the answer to that is:

* it leads to far more efficient performance when calling functions;

E.g. if the default value is expensive to calculate, it is better to
calculate it once, when the function is created, than every single time
the function is called.

Additionally, the effbot once mentioned in a similar thread that there
are real performance benefits in the Python VM from binding the default
value once only. I don't know the exact details of that, but I trust
Fredrik knows what he's talking about.
* it has less scope for surprise when calling functions.

E.g. I would argue that most people would be surprised, and dismayed, if
this code fails:

x = 1
def foo(a, b=x):
return a+b

del x
print foo(2)

From your post, it's hard to tell whether this 'duh'-type observation
would point out the salient feature of the construct, or whether you're
after something deeper.

If you're asking, 'Why isn't the argument list considered to be inside
the body?', then the answer is, it's pretty much arbitrary.
No, it is not an arbitrary choice. I've given practical reasons why the
Python choice is better. If you want default argument to be created from
scratch when the function is called, you can get it with little
inconvenience, but the opposite isn't true. It is very difficult to get
static default arguments given a hypothetical Python where default
arguments are created from scratch. There's no simple, easy idiom that
will work. The best I can come up with is a convention:

# Please don't change this, or strange things will happen.
_private = ResultOfExpensiveCalculation()

def foo(a, b=_private):
return a+b

The above is still vulnerable to code accidentally over-writing _private
with some other value, or deleting it, but at least we avoid the
expensive calculation every time.

Or possibly:

def foo(a, b=foo._private):
return a+b

foo._private = ResultOfExpensiveCalculation()

which has obvious disadvantages with regard to shadowing, renaming,
anonymous functions, and so forth.
Regardless
of which one the author of Python chose, the other's workaround would be
equally short,
Not true. One has an obvious workaround, the other only has a *partial*
workaround.
and neither one is obviously indicated by the syntax.
I would disagree, but not enough to argue.
--
Steven
Nov 16 '08 #5

P: n/a
Steven D'Aprano <st***@REMOVE-THIS-cybersource.com.auwrites:
On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
>Hello All,

Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.

That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different list
each time, you should have said so. Don't blame the language for doing
exactly what you told it to do.
Come on. The fact that this questions comes up so often (twice in 24h)
is proof that this is a surprising behaviour. I do think it is the
correct one but it is very natural to assume that when you write

def foo(bar=[]):
bar.append(6)
...

you are describing what happens when you _call_ foo, i.e.:

1. if bar is not provided, make it equal to []
2. Append 6 to bar
3. ...

--
Arnaud
Nov 16 '08 #6

P: n/a
On Nov 16, 2:05*am, Arnaud Delobelle <arno...@googlemail.comwrote:
Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.auwrites:
On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
Hello All,
Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.
That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different list
each time, you should have said so. Don't blame the language for doing
exactly what you told it to do.

Come on. *The fact that this questions comes up so often (twice in 24h)
is proof that this is a surprising behaviour. *I do think it is the
correct one but it is very natural to assume that when you write

* * def foo(bar=[]):
* * * * *bar.append(6)
* * * * *...

you are describing what happens when you _call_ foo, i.e.:

* * 1. if bar is not provided, make it equal to []
* * 2. Append 6 to bar
* * 3. ...
+1. Understanding and accepting the current behavior (mainly because
of the extra performance penalty of evaluating the default expressions
on every call would incur) is one thing, claiming that it is somehow
natural is plain silly, as dozens of threads keep showing time and
time again. For better or for worse the current semantics will
probably stay forever but I wish Python grows at least a syntax to
make the expected semantics easier to express, something like:

def foo(bar=`[]`):
bar.append(6)

where `expr` would mean "evaluate the expression in the function
body". Apart from the obvious usage for mutable objects, an added
benefit would be to have default arguments that depend on previous
arguments:

def foo(x, y=`x*x`, z=`x+y`):
return x+y+z

as opposed to the more verbose and less obvious current hack:

def foo(x, y=None, z=None):
if y is None: y = x*x
if z is None: z = x+y
return x+y+z

George
Nov 16 '08 #7

P: n/a
On Sun, 16 Nov 2008 07:05:51 +0000, Arnaud Delobelle wrote:
Steven D'Aprano <st***@REMOVE-THIS-cybersource.com.auwrites:
>On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
>>Hello All,

Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.

That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different
list each time, you should have said so. Don't blame the language for
doing exactly what you told it to do.

Come on. The fact that this questions comes up so often (twice in 24h)
is proof that this is a surprising behaviour.
Of course it's surprising. People make an assumption based on other
languages. But there is nothing "natural" about that assumption. It may
be common, but that doesn't mean it's the only way to think about it.

If you check the archives of this newsgroup, you will see that some time
not very long ago I made the suggestion that perhaps Python should raise
a warning when it creates a function with an obviously mutable default
argument. In practice, that would mean checking for three special cases:
[], {} and set(). So I'm sympathetic towards the surprise people feel,
but I don't agree that it is natural. "Natural" is a thought-stopper.
It's meant to imply that any other alternative is unnatural, crazy,
stupid, perverted, or whatever other alternative to natural you prefer,
therefore stop all disagreement.
I do think it is the
correct one but it is very natural to assume that when you write

def foo(bar=[]):
bar.append(6)
...

you are describing what happens when you _call_ foo, i.e.:

1. if bar is not provided, make it equal to []
2. Append 6 to bar
3. ...

Which is *exactly* what happens -- except of course once you append six
to the list [], it now looks like [6].

Why assume that "make it equal to []" implies a different list every
time, rather than that it is a specific list that happens to start off as
[]? Why isn't it equally "natural" to assume that it's the same list each
time, and it starts off as [] but need not stay that way?
--
Steven
Nov 16 '08 #8

P: n/a
George Sakkis wrote:
On Nov 16, 2:05 am, Arnaud Delobelle <arno...@googlemail.comwrote:
>Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.auwrites:
>>On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
Hello All,
Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.
That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different list
each time, you should have said so. Don't blame the language for doing
exactly what you told it to do.
Come on. The fact that this questions comes up so often (twice in 24h)
is proof that this is a surprising behaviour. I do think it is the
correct one but it is very natural to assume that when you write

def foo(bar=[]):
bar.append(6)
...

you are describing what happens when you _call_ foo, i.e.:

1. if bar is not provided, make it equal to []
2. Append 6 to bar
3. ...

+1. Understanding and accepting the current behavior (mainly because
of the extra performance penalty of evaluating the default expressions
on every call would incur) is one thing, claiming that it is somehow
natural is plain silly, as dozens of threads keep showing time and
time again. For better or for worse the current semantics will
probably stay forever but I wish Python grows at least a syntax to
make the expected semantics easier to express, something like:

def foo(bar=`[]`):
bar.append(6)

where `expr` would mean "evaluate the expression in the function
body". Apart from the obvious usage for mutable objects, an added
benefit would be to have default arguments that depend on previous
arguments:
Would you also retain the context surrounding the function declaration
so it's obvious how it will be evaluated, or would you limit the default
values to expressions with no bound variables?
def foo(x, y=`x*x`, z=`x+y`):
return x+y+z

as opposed to the more verbose and less obvious current hack:

def foo(x, y=None, z=None):
if y is None: y = x*x
if z is None: z = x+y
return x+y+z
"Less obvious" is entirely in the mind of the reader. However I can see
far more justification for the behavior Python currently exhibits than
the semantic time-bomb you are proposing.

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

Nov 16 '08 #9

P: n/a
George Sakkis wrote:
On Nov 16, 2:05 am, Arnaud Delobelle <arno...@googlemail.comwrote:
>Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.auwrites:
>>On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
Hello All,
Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.
That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different list
each time, you should have said so. Don't blame the language for doing
exactly what you told it to do.
Come on. The fact that this questions comes up so often (twice in 24h)
is proof that this is a surprising behaviour. I do think it is the
correct one but it is very natural to assume that when you write

def foo(bar=[]):
bar.append(6)
...

you are describing what happens when you _call_ foo, i.e.:

1. if bar is not provided, make it equal to []
2. Append 6 to bar
3. ...

+1. Understanding and accepting the current behavior (mainly because
of the extra performance penalty of evaluating the default expressions
on every call would incur) is one thing, claiming that it is somehow
natural is plain silly, as dozens of threads keep showing time and
time again. For better or for worse the current semantics will
probably stay forever but I wish Python grows at least a syntax to
make the expected semantics easier to express, something like:

def foo(bar=`[]`):
bar.append(6)

where `expr` would mean "evaluate the expression in the function
body". Apart from the obvious usage for mutable objects, an added
benefit would be to have default arguments that depend on previous
arguments:
Would you also retain the context surrounding the function declaration
so it's obvious how it will be evaluated, or would you limit the default
values to expressions with no bound variables?
def foo(x, y=`x*x`, z=`x+y`):
return x+y+z

as opposed to the more verbose and less obvious current hack:

def foo(x, y=None, z=None):
if y is None: y = x*x
if z is None: z = x+y
return x+y+z
"Less obvious" is entirely in the mind of the reader. However I can see
far more justification for the behavior Python currently exhibits than
the semantic time-bomb you are proposing.

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

Nov 16 '08 #10

P: n/a
Dennis Lee Bieber wrote:
On Sat, 15 Nov 2008 01:40:04 -0800 (PST), Rick Giuly
<rg**********@yahoo.comdeclaimed the following in comp.lang.python:
>Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.
This is a FAQ... default arguments are evaluation only ONCE, during
the "compilation" of the function.
>class Blob:
def __init__(self, points=[]):
self._points = points
The preferred/recommended form is to use (very explicit, one test,
one "assignment")

def __init__(self, points=None):
if points:
self._points = points
else:
self._points = []

or (shorter; one test, potentially two "assignments")

def __init__(self, points=None):
if not points: points = []
self._points = points
I hesitate to beat the thoroughly obvious to death with a stick, but
this is a *very* bad way to make the test. If you are using None as a
sentinel to indicate that no argument was provided to the call then the
correct test is

if points is None:
points = []

The code shown fails to distinguish between passing an empty list and
not passing an argument at all.

regards
Steve

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

Nov 16 '08 #11

P: n/a
On Nov 16, 8:28 am, Steve Holden <st...@holdenweb.comwrote:
>
+1. Understanding and accepting the current behavior (mainly because
of the extra performance penalty of evaluating the default expressions
on every call would incur) is one thing, claiming that it is somehow
natural is plain silly, as dozens of threads keep showing time and
time again. For better or for worse the current semantics will
probably stay forever but I wish Python grows at least a syntax to
make the expected semantics easier to express, something like:
def foo(bar=`[]`):
bar.append(6)
where `expr` would mean "evaluate the expression in the function
body". Apart from the obvious usage for mutable objects, an added
benefit would be to have default arguments that depend on previous
arguments:

Would you also retain the context surrounding the function declaration
so it's obvious how it will be evaluated, or would you limit the default
values to expressions with no bound variables?
No, all expressions would be allowed, and the semantics would be
identical to evaluating them in the function body; not context would
be necessary.
def foo(x, y=`x*x`, z=`x+y`):
return x+y+z
as opposed to the more verbose and less obvious current hack:
def foo(x, y=None, z=None):
if y is None: y = x*x
if z is None: z = x+y
return x+y+z

"Less obvious" is entirely in the mind of the reader.
Without documentation or peeking into the function body, a None
default conveys little or no information, so I don't think it's just
in the mind of the reader. Do you find the following less obvious than
the current workaround ?

from datetime import date
from timedelta import timedelta

def make_reservation(customer,
checkin=`date.today()`,
checkout=`checkin+timedelta(days=3)`):
...

However I can see
far more justification for the behavior Python currently exhibits than
the semantic time-bomb you are proposing.
I didn't propose replacing the current behavior (that would cause way
too much breakage), only adding a new syntax which is now invalid, so
one would have to specify it explicitly.

George
Nov 16 '08 #12

P: n/a
On Sun, Nov 16, 2008 at 11:02 AM, George Sakkis <ge***********@gmail.comwrote:
On Nov 16, 8:28 am, Steve Holden <st...@holdenweb.comwrote:
>>
+1. Understanding and accepting the current behavior (mainly because
of the extra performance penalty of evaluating the default expressions
on every call would incur) is one thing, claiming that it is somehow
natural is plain silly, as dozens of threads keep showing time and
time again. For better or for worse the current semantics will
probably stay forever but I wish Python grows at least a syntax to
make the expected semantics easier to express, something like:
def foo(bar=`[]`):
bar.append(6)
where `expr` would mean "evaluate the expression in the function
body". Apart from the obvious usage for mutable objects, an added
benefit would be to have default arguments that depend on previous
arguments:

Would you also retain the context surrounding the function declaration
so it's obvious how it will be evaluated, or would you limit the default
values to expressions with no bound variables?

No, all expressions would be allowed, and the semantics would be
identical to evaluating them in the function body; not context would
be necessary.
def foo(x, y=`x*x`, z=`x+y`):
return x+y+z
as opposed to the more verbose and less obvious current hack:
def foo(x, y=None, z=None):
if y is None: y = x*x
if z is None: z = x+y
return x+y+z

"Less obvious" is entirely in the mind of the reader.

Without documentation or peeking into the function body, a None
default conveys little or no information, so I don't think it's just
in the mind of the reader. Do you find the following less obvious than
the current workaround ?

from datetime import date
from timedelta import timedelta

def make_reservation(customer,
checkin=`date.today()`,
checkout=`checkin+timedelta(days=3)`):
...

>However I can see
far more justification for the behavior Python currently exhibits than
the semantic time-bomb you are proposing.

I didn't propose replacing the current behavior (that would cause way
too much breakage), only adding a new syntax which is now invalid, so
one would have to specify it explicitly.
Minor FYI, but Guido has proscribed backticks ever being used in
Python again. See http://www.python.org/dev/peps/pep-3099/

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
>
George
--
http://mail.python.org/mailman/listinfo/python-list
Nov 16 '08 #13

P: n/a
On Nov 16, 2:30*pm, "Chris Rebert" <c...@rebertia.comwrote:
On Sun, Nov 16, 2008 at 11:02 AM, George Sakkis <george.sak...@gmail.com>wrote:
On Nov 16, 8:28 am, Steve Holden <st...@holdenweb.comwrote:
"Less obvious" is entirely in the mind of the reader.
Without documentation or peeking into the function body, a None
default conveys little or no information, so I don't think it's just
in the mind of the reader. Do you find the following less obvious than
the current workaround ?
from datetime import date
from timedelta import timedelta
def make_reservation(customer,
* * * * * * * * * * checkin=`date.today()`,
* * * * * * * * * * checkout=`checkin+timedelta(days=3)`):
* ...
However I can see
far more justification for the behavior Python currently exhibits than
the semantic time-bomb you are proposing.
I didn't propose replacing the current behavior (that would cause way
too much breakage), only adding a new syntax which is now invalid, so
one would have to specify it explicitly.

Minor FYI, but Guido has proscribed backticks ever being used in
Python again. Seehttp://www.python.org/dev/peps/pep-3099/
I know, just used it for the sake of the example; the actual syntax is
much less of an issue in this case than the functionality.

George
Nov 16 '08 #14

P: n/a
On Nov 16, 4:05*am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
On Sun, 16 Nov 2008 07:05:51 +0000, Arnaud Delobelle wrote:
Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.auwrites:
On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
>Hello All,
>Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.
That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different
list each time, you should have said so. Don't blame the language for
doing exactly what you told it to do.
Come on. *The fact that this questions comes up so often (twice in 24h)
is proof that this is a surprising behaviour.

Of course it's surprising. People make an assumption based on other
languages. But there is nothing "natural" about that assumption. It may
be common, but that doesn't mean it's the only way to think about it.
My point is that neither one is more natural than the other. I think
that more than one person has shirked the burden of proof in making
claims about naturality, as well as overstepped the bounds of what a
conclusion about naturality entails. In other words, "Prove it. So
what?"

def f( a= [] ):
a.append( 0 )
return a

a= f()
b= f()
c= f( [] )

a== b!= c, because '[]' is not the default value, because '[] is not
[]'.

If I run 'a= []' ten times in a loop, '[]' is executed ten times. If
I call 'f' ten times, '[]' is only executed once. You do have a case
that the function is defined once, but executed ten times.
Why assume that "make it equal to []" implies a different list every
time, rather than that it is a specific list that happens to start off as
[]? Why isn't it equally "natural" to assume that it's the same list each
time, and it starts off as [] but need not stay that way?
In other words, what does 'natural' mean? Either provide an analytic
definition (strict necessary and sufficient conditions), or some
paradigm cases. 'Natural' in the sense that killing is natural? Are
there any such senses? Is natural always best? Is natural always
obvious?

Oddly, http://dictionary.reference.com/browse/natural has 38
definitions in the longest entry.
Nov 17 '08 #15

P: n/a
On Nov 16, 7:28*am, Steve Holden <st...@holdenweb.comwrote:
George Sakkis wrote:
On Nov 16, 2:05 am, Arnaud Delobelle <arno...@googlemail.comwrote:
Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.auwrites:
On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
Hello All,
Why is python designed so that b and c (according to code below)
actually share the same list object? It seems more natural to me that
each object would be created with a new list object in the points
variable.
That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different list
each time, you should have said so. Don't blame the language for doing
exactly what you told it to do.
Come on. *The fact that this questions comes up so often (twice in 24h)
is proof that this is a surprising behaviour. *I do think it is the
correct one but it is very natural to assume that when you write
* * def foo(bar=[]):
* * * * *bar.append(6)
* * * * *...
you are describing what happens when you _call_ foo, i.e.:
* * 1. if bar is not provided, make it equal to []
* * 2. Append 6 to bar
* * 3. ...
+1. Understanding and accepting the current behavior (mainly because
of the extra performance penalty of evaluating the default expressions
on every call would incur) is one thing, claiming that it is somehow
natural is plain silly, as dozens of threads keep showing time and
time again. For better or for worse the current semantics will
probably stay forever but I wish Python grows at least a syntax to
make the expected semantics easier to express, something like:
def foo(bar=`[]`):
* * bar.append(6)
where `expr` would mean "evaluate the expression in the function
body". Apart from the obvious usage for mutable objects, an added
benefit would be to have default arguments that depend on previous
arguments:

Would you also retain the context surrounding the function declaration
so it's obvious how it will be evaluated, or would you limit the default
values to expressions with no bound variables?
def foo(x, y=`x*x`, z=`x+y`):
* * return x+y+z
as opposed to the more verbose and less obvious current hack:
def foo(x, y=None, z=None):
* * if y is None: y = x*x
* * if z is None: z = x+y
* * return x+y+z

"Less obvious" is entirely in the mind of the reader. However I can see
far more justification for the behavior Python currently exhibits than
the semantic time-bomb you are proposing.
It is too bad you are not better at sharing what you see. I would
like to see 'far more' of it, if it's there.
Nov 17 '08 #16

P: n/a
On Nov 16, 12:52*am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
On Sat, 15 Nov 2008 21:29:22 -0800, Aaron Brady wrote:
....
If you want to be pedantic, then my "answer" (which you seem to approve
of) doesn't correspond to either of the original poster's questions. If
you're going to be pedantic, then be pedantic all the way, and criticize
me for answering a question that wasn't asked :-P
Not pedantic. He was questioning the reasons and motivation.

....
Actually, the correct answer to "Why?" would be "Because that's the
decision Guido van Rossum made back in the early 1990s when he first
started designing Python". That of course leads to the obvious question
"Why did he make that decision?", and the answer to that is:

* it leads to far more efficient performance when calling functions;

E.g. if the default value is expensive to calculate, it is better to
calculate it once, when the function is created, than every single time
the function is called.
It is best to calculate it just how many times you need to, and no
more.
Additionally, the effbot once mentioned in a similar thread that there
are real performance benefits in the Python VM from binding the default
value once only. I don't know the exact details of that, but I trust
Fredrik knows what he's talking about.

* it has less scope for surprise when calling functions.
Obviously, either behavior would be surprising to different sets of
people, with probably little overlap. Is one set larger, or has
certain characteristics, like contains more deep thinkers, etc.?
E.g. I would argue that most people would be surprised, and dismayed, if
this code fails:

x = 1
def foo(a, b=x):
* *return a+b

del x
print foo(2)
Point taken.
From your post, it's hard to tell whether this 'duh'-type observation
would point out the salient feature of the construct, or whether you're
after something deeper.
If you're asking, 'Why isn't the argument list considered to be inside
the body?', then the answer is, it's pretty much arbitrary.

No, it is not an arbitrary choice.
I didn't mean arbitrary as in out-of-the-blue. I meant arbitrary as
in dart-board decision from hand-picked possibilities, that is, that
the original decision maker thought, 'close call' between two, and
just picked one.

I have a different perspective than he did at the time, and he does
too now. It's not clear that if he came to think that the cases were
closer than he originally judged, he would say so, though knowing
humans at large, I'd guess that if the case was stronger, he would. I
would. Of course not just any human can invent Python.
I've given practical reasons why the
Python choice is better. If you want default argument to be created from
scratch when the function is called, you can get it with little
inconvenience, but the opposite isn't true. It is very difficult to get
static default arguments given a hypothetical Python where default
arguments are created from scratch. There's no simple, easy idiom that
will work. The best I can come up with is a convention:
I'm not so sure.

## Default evaluated at definition time. (Current.)

# Static arg.
def f( a= [] ):
...

# Non-static arg.
def f( a= None ):
if a is None: a= []

## Default evaluated at call-time. (Alternative.)

# Static arg.
@static( a= [] )
def f( a ):
...

# Non-static arg.
def f( a= [] ):
...

They're about the same difficulty. This comparison makes it look like
efficiency is the strongest argument-- just an 'if' vs. an entire
extra function call.
Nov 17 '08 #17

P: n/a
Aaron Brady wrote:
On Nov 16, 7:28 am, Steve Holden <st...@holdenweb.comwrote:
>George Sakkis wrote:
>>On Nov 16, 2:05 am, Arnaud Delobelle <arno...@googlemail.comwrote:
Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.auwrites:
On Sat, 15 Nov 2008 01:40:04 -0800, Rick Giuly wrote:
>Hello All,
>Why is python designed so that b and c (according to code below)
>actually share the same list object? It seems more natural to me that
>each object would be created with a new list object in the points
>variable.
That's not natural *at all*. You're initialising the argument "points"
with the same list every time. If you wanted it to have a different list
each time, you should have said so. Don't blame the language for doing
exactly what you told it to do.
Come on. The fact that this questions comes up so often (twice in 24h)
is proof that this is a surprising behaviour. I do think it is the
correct one but it is very natural to assume that when you write
def foo(bar=[]):
bar.append(6)
...
you are describing what happens when you _call_ foo, i.e.:
1. if bar is not provided, make it equal to []
2. Append 6 to bar
3. ...
+1. Understanding and accepting the current behavior (mainly because
of the extra performance penalty of evaluating the default expressions
on every call would incur) is one thing, claiming that it is somehow
natural is plain silly, as dozens of threads keep showing time and
time again. For better or for worse the current semantics will
probably stay forever but I wish Python grows at least a syntax to
make the expected semantics easier to express, something like:
def foo(bar=`[]`):
bar.append(6)
where `expr` would mean "evaluate the expression in the function
body". Apart from the obvious usage for mutable objects, an added
benefit would be to have default arguments that depend on previous
arguments:
Would you also retain the context surrounding the function declaration
so it's obvious how it will be evaluated, or would you limit the default
values to expressions with no bound variables?
>>def foo(x, y=`x*x`, z=`x+y`):
return x+y+z
as opposed to the more verbose and less obvious current hack:
def foo(x, y=None, z=None):
if y is None: y = x*x
if z is None: z = x+y
return x+y+z
"Less obvious" is entirely in the mind of the reader. However I can see
far more justification for the behavior Python currently exhibits than
the semantic time-bomb you are proposing.

It is too bad you are not better at sharing what you see. I would
like to see 'far more' of it, if it's there.
Well, briefly: it seems far simpler to me to use

def f(x=None):
if x is None:
x = <some value interpreted in the context of the current call>
...

than it does to use

def f(x=<some value to be interpreted in the context of the current call>):
...

particularly since at present the language contains no syntax for the
latter. But maybe I am focusing too much on the difficulty of compiling
whatever bizarre syntax is eventually adopted.

Understand, my point of view is biased by forty years of programming
experience, to the extent that I disagreed with Guido's proposal to make
integer division return a floating-point value. So I wouldn't
necessarily claim alignment with the majority.

Consider, though, the case were one argument value has to refer to
another. I would say the function body is the proper place to be doing
that computation. You appear to feel the def statement is the
appropriate place. If multiple statements are needed to perform the
argument initialization, how would you then propose the problem should
be solved?

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

Nov 17 '08 #18

P: n/a
On Nov 17, 12:27*pm, Steve Holden <st...@holdenweb.comwrote:
If multiple statements are needed to perform the
argument initialization, how would you then propose the problem should
be solved?
Why, with another function of course!

def f(x, y=`f_arg_computation(x)`): ...

Or my personal favourite:

def f(x, **`f_arg_computation(x)`): ...

Seriously, though, I agree with Steve; the function body -is- the
place for computation to occur.
Nov 17 '08 #19

P: n/a
For the Nth time this year that this has come up, I'll point out yet
again that this issue has already been discussed to death before:

[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

Result: Evaluating the arguments at runtime rather than
definition-time was deemed too magical; the backward compatibility
issues make changes unlikely; it's hard to find an acceptable syntax.

But hey, if some people want to have another go at it, best of luck.

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
On Sun, Nov 16, 2008 at 8:11 PM, alex23 <wu*****@gmail.comwrote:
On Nov 17, 12:27 pm, Steve Holden <st...@holdenweb.comwrote:
>If multiple statements are needed to perform the
argument initialization, how would you then propose the problem should
be solved?

Why, with another function of course!

def f(x, y=`f_arg_computation(x)`): ...

Or my personal favourite:

def f(x, **`f_arg_computation(x)`): ...

Seriously, though, I agree with Steve; the function body -is- the
place for computation to occur.
--
http://mail.python.org/mailman/listinfo/python-list
Nov 17 '08 #20

P: n/a
On Nov 16, 8:16*pm, Aaron Brady <castiro...@gmail.comwrote:
On Nov 16, 12:52*am, Steven D'Aprano <st...@REMOVE-THIS-
I've given practical reasons why the
Python choice is better. If you want default argument to be created from
scratch when the function is called, you can get it with little
inconvenience, but the opposite isn't true. It is very difficult to get
static default arguments given a hypothetical Python where default
arguments are created from scratch. There's no simple, easy idiom that
will work. The best I can come up with is a convention:

I'm not so sure.

## Default evaluated at definition time. *(Current.)

# Static arg.
def f( a= [] ):
* ...

# Non-static arg.
def f( a= None ):
* if a is None: a= []
Oops. Forgot one, after the subsequent posts.

# Non-static arg.
@nonstatic( a= list )
def f( a ):
...

This can achieve the 'if a is None' effect. 'nonstatic' takes a
callable or a string, '@nonstatic( a= "[]" )'.

I don't see a way to achieve George Sakkis's example:

if y is None: y = x*x
if z is None: z = x+y

Without a change to the language (the other options don't need one).

#emulates 'def foo(x, y=`x*x`, z=`x+y`):'
@nonstatic( y= 'x*x' ) #illegal
@nonstatic( z= 'x+y' ) #illegal
def foo(x, y, z):
return x+y+z
Nov 17 '08 #21

P: n/a
Thanks to all for your replies

All things considered, I vote for evaluating the arguments at runtime
(each time the function is called). Good reasons for this have already
been mentioned so I won't repeat them. A programming language is a
user interface of sorts. (Pretty much all languages are logical so
"correctness" is not what I'm meaning to discuss - I'm thinking about
usability.) Python provides, for the most part, an *excellent* user
interface to the programmer. Why not make it even "better" by
evaluating the arguments each time the function is called? It will be
harder to change the language 10 years from now, so why not change it
now?

(By "better" I mean that over many years of time programmers will be
more productive because the language will be learned a bit faster with
a fewer surprises - and still retain its power.)

-Rick

On Nov 16, 10:28 pm, "Chris Rebert" <c...@rebertia.comwrote:
For the Nth time this year that this has come up, I'll point out yet
again that this issue has already been discussed to death before:

[Python-ideas] proto-PEP: Fixing Non-constant Default Argumentshttp://mail.python.org/pipermail/python-ideas/2007-January/000121.html

[Python-3000] pre-PEP: Default Argument Expressionshttp://mail.python.org/pipermail/python-3000/2007-February/005704.html

Result: Evaluating the arguments at runtime rather than
definition-time was deemed too magical; the backward compatibility
issues make changes unlikely; it's hard to find an acceptable syntax.

But hey, if some people want to have another go at it, best of luck.

Cheers,
Chris
--
Follow the path of the Iguana...http://rebertia.com

On Sun, Nov 16, 2008 at 8:11 PM, alex23 <wuwe...@gmail.comwrote:
On Nov 17, 12:27 pm, Steve Holden <st...@holdenweb.comwrote:
If multiple statements are needed to perform the
argument initialization, how would you then propose the problem should
be solved?
Why, with another function of course!
def f(x, y=`f_arg_computation(x)`): ...
Or my personal favourite:
def f(x, **`f_arg_computation(x)`): ...
Seriously, though, I agree with Steve; the function body -is- the
place for computation to occur.
--
http://mail.python.org/mailman/listinfo/python-list
Nov 19 '08 #22

P: n/a
On Nov 19, 8:41*am, Rick Giuly <rgiuly.gr...@yahoo.comwrote:
Python provides, for the most part, an *excellent* user
interface to the programmer. Why not make it even "better"
by evaluating the arguments each time the function is called?
It will be harder to change the language 10 years from now,
so why not change it now?
You probably messed up with your time machine; "now" is 2008, not
1991 ;-)

George
Nov 19 '08 #23

P: n/a
On Nov 19, 12:05*pm, Dennis Lee Bieber <wlfr...@ix.netcom.comwrote:
>
* * * * I wouldn't expect a language like Ada to somehow re-evaluate a
default argument on each call; why would I expect Python to do such?
Lots of people do.

If you had a menu in a browser interface that had the items, say,
'Stop' and 'Reload', what would you expect to happen if you clicked on
them?
Nov 20 '08 #24

P: n/a
On Nov 20, 10:14*am, Aaron Brady <castiro...@gmail.comwrote:
If you had a menu in a browser interface that had the items, say,
'Stop' and 'Reload', what would you expect to happen if you clicked on
them?
If you had a keyword called 'def', which defined functions, would you
expect it to define said functions when it executed, or on each
function call?
Nov 20 '08 #25

P: n/a
On Nov 19, 7:58*pm, alex23 <wuwe...@gmail.comwrote:
On Nov 20, 10:14*am, Aaron Brady <castiro...@gmail.comwrote:
If you had a menu in a browser interface that had the items, say,
'Stop' and 'Reload', what would you expect to happen if you clicked on
them?

If you had a keyword called 'def', which defined functions, would you
expect it to define said functions when it executed, or on each
function call?
At first, I would expect it to define them at compile-time. Then,
when I learned there was no such thing, I would expect it to define
them at execute-time. What does that have to do with evaluating a
default argument?
Nov 20 '08 #26

P: n/a
On Nov 20, 10:42*pm, Aaron Brady <castiro...@gmail.comwrote:
At first, I would expect it to define them at compile-time. *Then,
when I learned there was no such thing, I would expect it to define
them at execute-time. *What does that have to do with evaluating a
default argument?
It has -everything- to do with it when we're talking about the
defining of functions, and certainly a lot more relevance than straw
man arguments on the behaviour of browser buttons.

You said that you "would expect it to define them at execute-time". So
is that when the interpreter first hits the def or when the
interpreter hits every single function call? Because I personally
consider it to clearly occur at the point of definition and not at the
point of calling.
Nov 20 '08 #27

P: n/a
On Nov 20, 5:54*pm, alex23 <wuwe...@gmail.comwrote:
On Nov 20, 10:42*pm, Aaron Brady <castiro...@gmail.comwrote:
At first, I would expect it to define them at compile-time. *Then,
when I learned there was no such thing, I would expect it to define
them at execute-time. *What does that have to do with evaluating a
default argument?

It has -everything- to do with it when we're talking about the
defining of functions, and certainly a lot more relevance than straw
man arguments on the behaviour of browser buttons.

You said that you "would expect it to define them at execute-time". So
is that when the interpreter first hits the def or when the
interpreter hits every single function call? Because I personally
consider it to clearly occur at the point of definition and not at the
point of calling.
Why, I would expect the interpreter to define the functions when it
first hits the def, that is, at the point of definition.
Nov 21 '08 #28

P: n/a
On Wed, 19 Nov 2008 10:05:23 -0800, Dennis Lee Bieber wrote:
Do you really want a "default" argument that changes value depending
upon actions performed in the /surrounding/ scope?
And if you do, it is easy to get:

default_y = "something"

def parrot(x, y=None):
if y is None:
y = default_y
--
Steven
Nov 21 '08 #29

P: n/a
On Wed, 19 Nov 2008 11:26:54 -0800, George Sakkis wrote:
On Nov 19, 1:05*pm, Dennis Lee Bieber <wlfr...@ix.netcom.comwrote:
>On Wed, 19 Nov 2008 05:41:57 -0800 (PST), Rick Giuly
<rgiuly.gr...@yahoo.comdeclaimed the following in comp.lang.python:
(By "better" I mean that over many years of time programmers will be
more productive because the language will be learned a bit faster
with a fewer surprises - and still retain its power.)

* * * * Your opinion... I'm sure there are some libraries out there
* * * * that
rely upon the current behavior

That's a straw man; of course they rely on it since they can. The same
would be even more true if the opposite behavior was selected from the
beginning, many more libraries would rely on it instead of (ab)using
None as default.
"Many more"? You're guessing. By memory, most uses in the standard
library for default values either use immutables (strings or ints), in
which case rebinding the default at runtime is irrelevant, or are using
None to trigger special behaviour. (Please feel free to go through the
std lib and verify my feeble memories.) The *specific* gotcha people are
complaining about only affects a tiny proportion of default values: in
practice, it is almost always either [] or {}.

It seems a waste to have Python pay the cost of re-evaluating all those
default=0 and default=None calls just to satisfy a small proportion of
users whose intuition about Python's behaviour happens to be wrong. Since
that intuition has real costs and the current behaviour has real
benefits, people should just learn the Python way.

(I'm sympathetic for requests for syntactic sugar to get runtime
evaluation of defaults. I'm not sympathetic at all for requests to change
the default behaviour.)
That's the only argument that may worth some merit. It's interesting
though that C++, a language much more obsessed with performance, picks
the runtime semantics:
You're not going to hold C++ up as a shining beacon of the right way to
do things, are you?

--
Steven
Nov 21 '08 #30

P: n/a
On Thu, 20 Nov 2008 04:42:24 -0800, Aaron Brady wrote:
On Nov 19, 7:58*pm, alex23 <wuwe...@gmail.comwrote:
>On Nov 20, 10:14*am, Aaron Brady <castiro...@gmail.comwrote:
If you had a menu in a browser interface that had the items, say,
'Stop' and 'Reload', what would you expect to happen if you clicked
on them?

If you had a keyword called 'def', which defined functions, would you
expect it to define said functions when it executed, or on each
function call?

At first, I would expect it to define them at compile-time. Then, when
I learned there was no such thing,
Of course there is compile-time. When did you think the .pyc files got
created?

The same thing happens in the interactive interpreter: the function is
compiled to byte-code, and then the compiled function is executed by the
VM.

--
Steven
Nov 21 '08 #31

P: n/a
On Nov 21, 10:07*am, Aaron Brady <castiro...@gmail.comwrote:
Why, I would expect the interpreter to define the functions when it
first hits the def, that is, at the point of definition.
Then why are you arguing that the parameters should be re-defined at
the point of calling?

Nov 21 '08 #32

P: n/a
On Thu, Nov 20, 2008 at 9:26 PM, alex23 <wu*****@gmail.comwrote:
On Nov 21, 10:07 am, Aaron Brady <castiro...@gmail.comwrote:
>Why, I would expect the interpreter to define the functions when it
first hits the def, that is, at the point of definition.

Then why are you arguing that the parameters should be re-defined at
the point of calling?
I would assume because using the "def is start of definition" theory,
anything after the "def" is part of the function definition/body and
should not be immediately executed, but rather be executed at
call-time. The function body comes after the "def" and doesn't get run
immediately, so neither should the default argument values.

I take no position on the virtue of said theory.

Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
>
--
http://mail.python.org/mailman/listinfo/python-list
Nov 21 '08 #33

P: n/a
On Nov 20, 11:26*pm, alex23 <wuwe...@gmail.comwrote:
On Nov 21, 10:07*am, Aaron Brady <castiro...@gmail.comwrote:
Why, I would expect the interpreter to define the functions when it
first hits the def, that is, at the point of definition.

Then why are you arguing that the parameters should be re-defined at
the point of calling?
Hmm. You have conflated defining the function with defining the
parameters.

My argument is that the syntax doesn't obviously imply either
interpretation.

I advocate a 'nonstatic' decorator. Also, I don't think a 'static'
decorator, had Python taken the other interpretation, would have been
that bad a combination.
Nov 21 '08 #34

P: n/a
On Nov 21, 7:49*pm, Aaron Brady <castiro...@gmail.comwrote:
On Nov 20, 11:26*pm, alex23 <wuwe...@gmail.comwrote:
On Nov 21, 10:07*am, Aaron Brady <castiro...@gmail.comwrote:
Why, I would expect the interpreter to define the functions when it
first hits the def, that is, at the point of definition.
Then why are you arguing that the parameters should be re-defined at
the point of calling?

Hmm. *You have conflated defining the function with defining the
parameters.
No, I think I've made the mistake of joining yet another pointless
thread arguing about semantics.

Nov 21 '08 #35

P: n/a
On Nov 21, 4:24*am, alex23 <wuwe...@gmail.comwrote:
On Nov 21, 7:49*pm, Aaron Brady <castiro...@gmail.comwrote:
On Nov 20, 11:26*pm, alex23 <wuwe...@gmail.comwrote:
On Nov 21, 10:07*am, Aaron Brady <castiro...@gmail.comwrote:
Why, I would expect the interpreter to define the functions when it
first hits the def, that is, at the point of definition.
Then why are you arguing that the parameters should be re-defined at
the point of calling?
Hmm. *You have conflated defining the function with defining the
parameters.

No, I think I've made the mistake of joining yet another pointless
thread arguing about semantics.
I was making the case that the options were about the same. Then you
had some questions.

I said, I would expect the interpreter to define the functions at a
certain time.

You asked, why are you arguing that the parameters should be re-
defined at a different time.

You assumed that defining a function and defining its parameters
necessarily happen at the same time. Not so.
Nov 21 '08 #36

This discussion thread is closed

Replies have been disabled for this discussion.