Python: Unwanted Change Of Variable Occurs
Solution 1:
I'm not 100% sure about this but I suspect the problem is that variables in Python are references and not values. That is to say, when you set seq[i] = self.rule
, seq[i]
points to where self.rule
is stored in memory and any changes made to seq[i]
's value results in a change to self.rule
since their values are stored at the same location in memory.
What you probably should do is deep copy self.rule
's value into seq[i]
rather than simply assign it so that they use two different memory addresses to store their values (see http://docs.python.org/library/copy.html for more information), that way assigning to seq[i]
won't affect self.rule
.
Solution 2:
Default arguments are evaluated once when the function is defined, and reused later.
def f(x, a = [])
a.append(x)
return a
print f(0)
print f(1)
prints
[0]
[0, 1]
The usual way to avoid this problem is to use None
as default parameter:
deff(x, a = None):
if a isNone:
a = []
# ...
See the Python tutorial for a detailed explanation.
Solution 3:
I'm not sure if this is the problem, but you have to be very careful about setting a default list in a function like this:
def__init__(self,bind="F",rule=["F"]):
self.bind = bind
self.rule = rule
Each time you call this function, it's going to use the same list every time! Therefore, every time you modify self.rule
in one Rule object, you are modifying it in every other object you have.
Instead, you should do this:
def__init__(self,bind="F",rule=None):
self.bind = bind
ifnot rule:
self.rule = ['F']
else:
self.rule = rule
This way, you create a new list object every time, instead of reusing the same one.
For example:
classfoo:
def__init__(self, x=[]):
self.x = x
self.x.append(3)
d = foo()
e = foo()
f = foo()
print f.x # prints [3,3,3]
Solution 4:
It changes because rule
is a reference to a list. You then assign seq[i]
to refer to the object pointed to by self.rule
. So when you modify seq
, you're modifying the same object referenced by self.rule.
>>>a = [1,2,3,4]>>>b = a>>>b.append(5)>>>print a
[1, 2, 3, 4, 5]
I believe that what you are looking for is a copy of the list stored in rule
. This can be done in a couple ways. In the first, you construct a new list from the current iterable.
seq[i] = list(self.rule) # Makes a new list that is a copy of self.rule
If self.rule
contains a list of immutables (integers, strings, etc.), then that should be sufficient. If, however, self.rule
contains mutables, like class instances, then what you'll end up with is a new list that references all of the same objects that were referenced in self.rule
. What that means can be seen in the following code:
>>>classA(object):...def__init__(self, val):... self.x = val>>>a = [A(i) for i in xrange(10)]>>>print a[0].x
0
>>>print a[1].x
1
>>>b = list(a)>>>b.append(A(10))>>>print b[0].x
0
>>>b[0].x = 99>>>print b[0].x
99
>>>print a[0].x
99
>>>print (len(a), len(b))
(10, 11)
Here we have two different lists, but two different lists that both have 10 references in common. List b
has an additional reference, further cementing its difference. To avoid that issue, you can use the second method, the deepcopy
.
>>>from copy import deepcopy>>>a = [A(i) for i in xrange(10)]>>>b = deepcopy(a)>>>b[0].x = 99>>>print b[0].x
99
>>>print a[0].x
0
This makes a copy of the list and all of the objects in that list.
Finally, I have to caution you against using a list as a default value for the rule
keyword argument. That almost certainly will not work the way you expect. The keyword argument rule
gets an instance of the list ["F"]
at definition. All calls to __init__
will get the same list instance, so modifying that list will affect the default behavior as rule
changes. See Default value of memberfunction for another example.
Post a Comment for "Python: Unwanted Change Of Variable Occurs"