473,385 Members | 1,582 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,385 software developers and data experts.

bug or feature?

Coming back from a bug hunt, i am not sure what to think of this python
behaviour. Here is a demo program:

class A:
def __init__(self, lst=[]):
self.lst = lst

a = A()
b = A()
b.lst.append("hallo")
print a.lst # output: ["hallo"]

The point seems to be, that lst=[] creates a class attribute (correct
name?), which is shared by all instances of A. So a.lst ist the same
object as b.lst, despite the fact, that object a is different to object
b.

Oct 5 '05 #1
11 1276
beza1e1 wrote:
Coming back from a bug hunt, i am not sure what to think of this python
behaviour. Here is a demo program:

class A:
def __init__(self, lst=[]):
self.lst = lst

a = A()
b = A()
b.lst.append("hallo")
print a.lst # output: ["hallo"]

The point seems to be, that lst=[] creates a class attribute (correct
name?), which is shared by all instances of A. So a.lst ist the same
object as b.lst, despite the fact, that object a is different to object
b.


It is an *instance attribute* by nature, since it does not reside in the
class object, but only in its instances. The truth is, that a.lst and
b.lst point to the same memory object, so it seems to behave much like
the class attribute :)

It is no more different from the simple fact, that two variables
(attributes) may point to the same memory object, like you see below:

a = b = []
a.append("hallo")
print b #output: ["hallo"]

In fact, it is usually a bad practice to assign instance attributes a
reference to the compound variable, existing in an external scope. Example:

aList = []

class A:
def __init__(self, lst): #no default attribute!
self.lst = lst

a = A(aList)
aList.append("hallo")
print a.lst #output: ["hallo"]

and your default value (, lst=[]) IS such an variable! The bad thing is,
that the value of the instance attribute 'lst' (example above) depends
on the external variable, which may be independently modified, thus
modifying unexpectedly the instance attribute. The safer approach, of
course is to write:

class A:
def __init__(self, lst): #no default attribute!
self.lst = lst[:] #take a copy

Summing up, is it an error, or a feature? I would say - a feature.
Everyone should be aware, that the argument default values are evaluated
once, and the same value (memory object) is reused at each instance
creation.

Best regards,
Tomasz Lisowski
Oct 5 '05 #2
Python.org General FAQ 1.4.21: Why are default values shared between
objects?
(http://www.python.org/doc/faq/genera...etween-objects)

Oct 5 '05 #3

beza1e1> class A:
beza1e1> def __init__(self, lst=[]):
beza1e1> self.lst = lst

Lists are mutable and default args are only evaluated once, at function
definition. If you want independent default args use:

class A:
def __init__(self, lst=None):
if lst is None:
lst = []
self.lst = lst

The same scheme would work for other mutable types (dicts, sets, etc).

This same question gets asked once a month or so. I'm sure this is in the
Python FAQ (check the website), but it was faster to reply than to look it
up...

Skip
Oct 5 '05 #4
beza1e1 wrote:
Coming back from a bug hunt, i am not sure what to think of this python
behaviour. Here is a demo program:

class A:
def __init__(self, lst=[]):
self.lst = lst

a = A()
b = A()
b.lst.append("hallo")
print a.lst # output: ["hallo"]

The point seems to be, that lst=[] creates a class attribute (correct
name?), which is shared by all instances of A. So a.lst ist the same
object as b.lst, despite the fact, that object a is different to object
b.

Interestingly I couldn't find this in the FAQ, though it *is* a
frequently-asked question [note: my not finding it doesn't guarantee
it's not there]. The nearest I could get was in
http://www.python.org/doc/faq/progra...-i-speed-it-up

which says:

"""Default arguments can be used to determine values once, at compile
time instead of at run time."""

The point is that the value of the keyword argument is determined when
the def statement is executed (which is to say when the function body is
being bound to its name).

If the default argument is (a reference to) a mutable object (such as a
list instance) then if one call to the function modifies that mutable
object, subsequent calls see the mutated instance as the default value.

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006 www.python.org/pycon/

Oct 5 '05 #5
Steve Holden wrote:
Interestingly I couldn't find this in the FAQ, though it *is* a
frequently-asked question [note: my not finding it doesn't guarantee
it's not there].


it's there:

http://www.python.org/doc/faq/genera...etween-objects

(maybe "default values" should be changed to "default argument values")

it's also mentioned in chapter 4 of the tutorial:

http://docs.python.org/tut/node6.htm...00000000000000

"*Important warning*: The default value is evaluated only once. This
makes a difference when the default is a mutable object such as a list,
dictionary, or instances of most classes. "

(the text then illustrates this with examples, and shows how to do things
instead)

and in the description of "def" in the language reference:

http://docs.python.org/ref/function.html

"*Default parameter values are evaluated when the function definition
is executed*. This means that the expression is evaluated once, when the
function is defined, and that that same "pre-computed" value is used for
each call. This is especially important to understand when a default para-
meter is a mutable object, such as a list or a dictionary: if the function
modifies the object (e.g. by appending an item to a list), the default
value is in effect modified."

(the text then shows how to do things instead)

</F>

Oct 5 '05 #6
Thanks for you answer! This copy trick is the most elegant solution i
think.

Oct 5 '05 #7
On Wed, 05 Oct 2005 03:39:30 -0700, beza1e1 wrote:
Coming back from a bug hunt, i am not sure what to think of this python
behaviour.
[snip code]
The point seems to be, that lst=[] creates a class attribute (correct
name?), which is shared by all instances of A. So a.lst ist the same
object as b.lst, despite the fact, that object a is different to object
b.


Not a bug, but not really a feature as such, it is a side-effect of
the way Python works. I guess that makes it a gotcha.

Argument defaults are set at compile time. You set the argument default to
a mutable object, an empty list. Every time you call the function,
you are appending to the same list.

This is not a problem if your argument default is a string, or a number,
or None, since these are all immutable objects that can't be changed.

I suppose someone might be able to come up with code that deliberately
uses this feature for good use, but in general it is something you want to
avoid. Instead of:

def spam(obj, L=[]):
L.append(obj)

do this:

def spam(obj, L=None):
if L is None: L = []
L.append(obj)
--
Steven.

Oct 5 '05 #8
Fredrik Lundh wrote:
it's also mentioned in chapter 4 of the tutorial:

http://docs.python.org/tut/node6.htm...00000000000000

"*Important warning*: The default value is evaluated only once. This
makes a difference when the default is a mutable object such as a list,
dictionary, or instances of most classes. "


Perhaps it would be a good idea if Python actually raised a warning
(SyntaxWarning?) if you use an unnamed list or dict as a default
argument. This would doubtless help quite a few beginners. And for
people who really do want that behaviour, working around the warning
should involve minimal extra code, with extra clarity thrown in for
free.

--
Ben Sizer

Oct 5 '05 #9
beza1e1:
Coming back from a bug hunt, i am not sure what to think of this python
behaviour. Here is a demo program:

class A:
def __init__(self, lst=[]):
self.lst = lst

a = A()
b = A()
b.lst.append("hallo")
print a.lst # output: ["hallo"]

The point seems to be, that lst=[] creates a class attribute (correct
name?), which is shared by all instances of A. So a.lst ist the same
object as b.lst, despite the fact, that object a is different to object
b.
Fredrik Lundh wrote: Steve Holden wrote:

Interestingly I couldn't find this in the FAQ, though it *is* a
frequently-asked question [note: my not finding it doesn't guarantee
it's not there].

it's there:

http://www.python.org/doc/faq/genera...etween-objects

(maybe "default values" should be changed to "default argument values")

I couldn't believe it wasn't, but you're right: it should be easier to
find, and a change of wording may do that.

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006 www.python.org/pycon/

Oct 5 '05 #10
Ben Sizer wrote:
Fredrik Lundh wrote:

it's also mentioned in chapter 4 of the tutorial:

http://docs.python.org/tut/node6.htm...00000000000000

"*Important warning*: The default value is evaluated only once. This
makes a difference when the default is a mutable object such as a list,
dictionary, or instances of most classes. "

Perhaps it would be a good idea if Python actually raised a warning
(SyntaxWarning?) if you use an unnamed list or dict as a default
argument. This would doubtless help quite a few beginners. And for
people who really do want that behaviour, working around the warning
should involve minimal extra code, with extra clarity thrown in for
free.

This would have to be extended to any mutable object. How does the
compiler know which objects are mutable?

This would not be a good change.

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006 www.python.org/pycon/

Oct 5 '05 #11
Steven D'Aprano wrote:
I suppose someone might be able to come up with code that deliberately
uses this feature for good use


argument binding is commonly used for optimization, and to give simple
functions persistent storage (e.g. memoization caches).

more importantly, it's the standard pydiom for passing object *values* (of
any kind) into an inner scope:

x = something

def myfunc(arg, x=x):
# myfunc needs the current value, not whatever x
# happens to be when the function is called

here's a typical gotcha:

for i in range(10):
def cb():
print "slot", i, "fired"
register_callback(slot=i, callback=cb)

to make this work as expected, you have to do

for i in range(10):
def cb(i=i):
print "slot", i, "fired"
register_callback(slot=i, callback=cb)

</F>

Oct 6 '05 #12

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

Similar topics

3
by: dayzman | last post by:
Hi, I've read somewhere that feature-based analysis can be used to extract the semantic structure of HTML documents. By semantic structure, they mean the model of the rendered view a reader...
5
by: scsharma | last post by:
Hi, I am using .Net on Windows XP Professional. I am facing a unique problem with visual studio where intellisense feature is getting turned off. If i close IDE and reopen my solution the...
4
by: christopher diggins | last post by:
A feature that I find signficantly missing in C# is the ability to write functions in interfaces that can call other functions of the interface. Given an interface ISomeInteface the only way we can...
18
by: Kamen Yotov | last post by:
hi all, i first posted this on http://msdn.microsoft.com/vcsharp/team/language/ask/default.aspx (ask a c# language designer) a couple of days ago, but no response so far... therefore, i am...
7
by: Russell Mangel | last post by:
I was thinking about what IDE feature I would want the most in the next version of VC++? I would definately ask for the C# feature: #region / #endregion. In my opinion this feature was a...
30
by: Raymond Hettinger | last post by:
Proposal -------- I am gathering data to evaluate a request for an alternate version of itertools.izip() with a None fill-in feature like that for the built-in map() function: >>> map(None,...
12
by: Raymond Hettinger | last post by:
I am evaluating a request for an alternate version of itertools.izip() that has a None fill-in feature like the built-in map function: >>> map(None, 'abc', '12345') # demonstrate map's None...
12
by: =?Utf-8?B?RGFyYSBQ?= | last post by:
Would like to know from the crowd that why do we require a Partial Class. By having such feature aren't we going out of the scope of Entity Concept. Help me to understand in what context this...
20
by: Luke R | last post by:
One thing i used to use alot in vb6 was that tiny little button in the bottom left of the code window which allowed you to view either the whole code file, or just the function/sub you are currenly...
10
by: Conrad Lender | last post by:
In a recent thread in this group, I said that in some cases object detection and feature tests weren't sufficient in the development of cross-browser applications, and that there were situations...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
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?
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
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...
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
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

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.