This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 9 years ago.
Is the default argument list the same object for all instances?
class X():
def __init__(self,a=[]):
self.member=a
print id(a)
k=X([1,2,3])
g=X([1,2,3])
t=X()
h=X()
The output surprises me:
140072782781832
140072782901976
140072782816536
140072782816536
As you can see, the id is different when a equals [1,2,3] but stays the same when a is empty. However, if I delete self.member, now the code looks like this:
class X():
def __init__(self,a=[]):
print id(a)
k=X([1,2,3])
g=X([1,2,3])
t=X()
h=X()
The output becomes like this:
140033294171528
140033294171528
140033294206232
140033294206232
The id stay the same when a equals [1,2,3].
I am totally confused... Anyone can explain that?
Yes, which is why you are supposed to do
class X():
def __init__(self, a=None):
self.a = [] if a is None else a
Edit:
I would point out that
class X():
def __init__(self,a=[]):
print(id(a))
k = X([1,2,3])
g = X([1,2,4]) # <- different list values
t = X()
h = X()
also gives
42678232
42678232
42680152
42680152
so I would expect the answer is something like "if you create a list, delete it, and create another list, the odds are good it will reuse the same allocated memory location".
Related
This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 5 years ago.
I would like to change the value of a member of an object. I can do this as long as i adress the object itself. However when I store a reference to this member it doesn't work. Instead it changes the reference object.
class MyClass:
def __init__(self, name):
self.a = 1
self.b = name
obj1=MyClass("string")
refob1=obj1.a
refob2=obj1.b
#I can change my object like this:
obj1.a=99
obj2.b="changed"
#But not like this:
refob1 = 1
refob2 = "changed_reference"
How can I use the reference object to change the members?
This is because int and strings in python are non-mutable objects. This means that they pass a copy of the value instead of the reference.
lists, in the other hand, are mutable objects and allow your desired behavior. Here you have an example:
class MyClass(object):
def __init__(self):
self.a = 3
self.b = [1]
obj = MyClass()
outside_a = obj.a
outside_a = 3 # outside_a is just a copy of obj.a value, so it won't change obj object
outisde_b = obj.b
outside_b[0] = 3 # Lists are mutabe, so this will change obj.b value
print obj.b # Prints [3]
So, how can you go around this? It is a bit ugly, but you can use a container (list) to contain the variables you want to reference later on. Here you can find a related post: Python passing an integer by reference
This question already has answers here:
Copy constructor in python?
(8 answers)
Closed 6 years ago.
In C++, the constructor of a class allows an instance to be constructed from another instance. e.g.
C::C(const C & c) {
bala...;
cc = c.cc;
}
In Python, what is the similar way of doing this? How may I use
c1 = C()
c2 = C(c1)
?
We don't mention the type while defining a variable in python. For example: if x=4, you can always set x to something else, x="shasha". No problem at all.
Note we can not overload a method in python.
Coming back to your question:
Assuming that you understand the python memory management and the difference between a reference and an actual value, You may use deepcopy feature in python:
import copy
class A(object):
def __init__(self):
self.a=10
x = A()
y= copy.deepcopy(x)
x.a=15
print(y.a) # prints 10.
Note that you can always copy one object into another using = operator like y = x but it wont actually copy anything. Now both the references y and x will actually be pointing to the same instance. i.e. if you change anything using one, it will automatically be reflected into the other one:
class A(object):
def __init__(self):
self.a=10
x = A()
y = x
x.a=15
print(y.a) # prints 15.
You can also create a dummy constructor as mentioned in following example:
class A:
def __init__(self):
self.a=10
def dummy_constructor(self):
temp = A()
temp.a = (self.a + 20 - 5 )*100/10
return temp
x=A()
y=x.dummy_constructor()
print(y.a) #250
print(x.a) #10
This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 7 years ago.
I'm defining a dictionary within a class (let's call it Thingy). Sometimes I need to use other Thingy instances as keys in the dictionary for thing1. However, if I try to add thing2 as a key with value 1 (say) to the dictionary of thing1, then thing2:1 also appears in the dict of thing2!
Please confirm if you can reproduce (python 2.7.6):
# class definition
class Thingy:
def __init__(self, d={}):
self.dict = d
# Test code
thing1 = Thingy()
thing2 = Thingy()
thing1.dict[thing2] = 1
print('Thing1.dict is {}'.format(thing1.dict))
print('Thing2.dict is {}'.format(thing2.dict))
gives me
Thing1.dict is {<__main__.Thingy instance at 0x7f79fdeed998>: 1}
Thing2.dict is {<__main__.Thingy instance at 0x7f79fdeed998>: 1}
even though I never changed Thing2.dict!
Never use mutable objects as default parameter:
class Thingy:
def __init__(self, d={}):
This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 9 years ago.
I am confusing about the default arguments in Python. Here are my code:
#!/usr/bin/env python
import sys
class Node(object):
def __init__(self, ID=str(), items=[]):
self.ID = ID
self.items = items
if __name__ == '__main__':
a = Node('1')
b = Node('2')
b.items.append('sth.')
c = Node('3')
print a.items
print b.items
print c.items
The output is:
['sth.']
['sth.']
['sth.']
I just change the b instance. Why all instances are changed?
This is a case of reference. Since the list items is mutable (can be directly changed with an internal method), any change you make to it in any function is reflected in all references to it.
For example, if you have the following code:
def f(x):
x.append(5)
a = [1, 2, 3]
f(a)
# a is now [1, 2, 3, 4], even in the global scope
This occurs because a is a mutable list, and so it is passed by reference.
So when you use items = [], you are creating a blank list when the program is started, but not every time you create a new instance. Instead, each instance refers to the same list, created when the class was "declared". So, since each instance refers to the same list, they are all changed.
To fix this, change your constructor to:
def __init__(self, ID=str(), items=None): # you can also use '' instead of str()
if not items: items = []
# everything else
A few good links to explain this better/in a different way:
Immutable Objects and References
Mutable Default Arguments
Default List Arguments
There are a ton of other questions like this out there, just search [python] None as default argument.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
“Least Astonishment” in Python: The Mutable Default Argument
I just want to check that the way I'm expecting this to work is correct or not. Here is a simplified version of a class I'm writing:
class Foo(object):
def __init__(self):
pass
def bar(self, test1=[], test2=[]):
if test2:
test1.append(1)
print test1
Now, to me, test1 and test2 - unless set - should always be set as empty lists when the function bar is called. This means that when test1 is printed, there should only ever be one item in the list (provided you only give one item as an argument). However, this is not the case:
>>> i = Foo()
>>> i.bar()
[]
>>> i.bar(test2=[1])
[1]
>>> i.bar()
[1, 1]
>>> i.bar(test2=[1])
[1, 1, 1]
In this case, you'd expect a similar result using integers:
class Foo(object):
def __init__(self):
pass
def bar(self, test1=0, test2=0):
if test2:
test1 += 1
print test1
But here, test1 is always set to 0:
>>> i = Foo()
>>> i.bar()
0
>>> i.bar(test2=1)
1
>>> i.bar(test2=1)
1
>>> i.bar(test2=1)
1
It seems that the list is persistent in the function or class's namespace, but the integer is not.
This may be a misunderstanding on my part, so would just like some clarification.
The default arguments of a function are set when the function is declared, not every time you call the function. Therefore the list that is made when the function is declared is only made once, and is referenced every other time you called the function. See also this question.
Because lists are mutable, when you change them, anything that references it changes as well. However integers are immutable (they can't be changed), so when you reassign a variable to another integer, only that variable changes, because it is referencing a different object.