473,809 Members | 2,695 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Optional parameter object re-used when instantiating multiple objects

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.appen d(1)
c._points.appen d(2)

print b._points

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



Nov 15 '08 #1
35 1975
Rick Giuly <rg**********@y ahoo.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.appen d(1)
c._points.appen d(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
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
On Nov 15, 3:40*am, Rick Giuly <rgiuly.gr...@y ahoo.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.appen d(1)
c._points.appen d(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
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 = ResultOfExpensi veCalculation()

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 = ResultOfExpensi veCalculation()

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
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
On Nov 16, 2:05*am, Arnaud Delobelle <arno...@google mail.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
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
George Sakkis wrote:
On Nov 16, 2:05 am, Arnaud Delobelle <arno...@google mail.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
Dennis Lee Bieber wrote:
On Sat, 15 Nov 2008 01:40:04 -0800 (PST), Rick Giuly
<rg**********@y ahoo.comdeclaim ed the following in comp.lang.pytho n:
>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 "compilatio n" 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 "assignment s")

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 #10

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

Similar topics

3
4346
by: Rane Bowen | last post by:
Hi, I am using python with a makepy generated wrapper on a COM application. One of this object's methods has 3 parameters, two of which are optional. If I call the method with just the non-optional parameter, or all three parameters, it works. If I call it with the first two parameters, I get the following error: (-2147352567, 'Exception occurred.', (0, 'Amphora.Session.1', 'A bad parameter was passed to the method', None, 0,...
7
36600
by: JT | last post by:
how can i declare a function that will accept an optional parameter? something like: function newFunc(strValue1, strValue2) --where strValue2 is optional. thanks much.
6
2148
by: spammy | last post by:
Hi all, Im attempting to use a COM class in C# via .NET interop. The class has two modes - synhrounous and asynchronous. The mode is determined by the use (or not) of an optional out parameter: COMClass test = new COMClass(); object results = null;
6
2617
by: Otto Wyss | last post by:
I've the following function declaration: wxTree GetLastChild (const wxTree& item, long& cookie) const; I'd like to make the cookie parameter optional, i.e. "long& cookie = ....", without breaking any software using the old API. The implementation looks like wxTree wxTreeListMainWindow::GetLastChild (const wxTree& item, long& cookie) const {
13
2521
by: William Ryan | last post by:
I just picked up a copy of John Robbins' debugging book and started to look at disassembled code. Anyway, I hate optional Parameters in VB, but I was checking them out to see what IL is created. I've done this before with Modules, and saw that <gasp> they behave just like sealed classes with only static members. Anyway, it looks like Optional Parameters are nothing but a way to tell the compiler to write some overloads for you. So, in...
4
3794
by: Yong Jiang | last post by:
I am trying to convert some vb code calling COM oboject methods to C#. Example shown as follows Dim Stream As New ADODB.Stream Call Stream.Open() Stream.Open has three optional parameters. I am trying to convert it to C# as shown as follows ADODB.Stream Stream = null;
1
2045
by: Hanover | last post by:
In at typical SQL command if I want an optional parameter, I say "Where ID=@ID or @ID=Null" This way if I dont pass in a parameter, it will just pull all of the IDs. Is there a way to set this up in the text command of a SQLCommand object in .NET?
2
11947
by: Oenone | last post by:
In our applications, we use the special value of DateTime.MinValue to represent "null dates" throughout all our code. We recently ran into an issue where we wanted an optional date parameter for a procedure. We weren't able to declare it with DateTime.MinValue as its default value, as MinValue is a read-only property rather than a constant. To work around, we had to use a "magic date" that we checked for later on. I was never very happy...
7
13476
by: Sam Shrefler | last post by:
I'm working on creating a WebService / WebMethod to receive a record in real time from another system. The record contains about 20 fields. 10 of which aren't required. I was planning on just making a method with 20 parameters. But, I see there is no way to make an "optional" c# parameter. I was just wondering if anyone had an suggestions on how to implement this? The parameters are all different primitive types (int, string,...
9
3881
by: =?Utf-8?B?V2ViQnVpbGRlcjQ1MQ==?= | last post by:
I'll ask, how do you do it? -- (i''ll be asking a lot of these, but I find C# totally way cooler than vb and there''s no go''n back!!!) thanks (as always) kes
0
9602
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10639
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10120
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9200
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, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7661
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5688
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4332
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3861
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
3015
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.