Вопрос

So while testing some code I discovered some odd functionality in Python, namely two variables with different values evaluating as equal. The code that produces said behavior is as follows

class Foo:
    def __init__(self):
        self.x = [1,2,3]
        self.y = self.x

    def ChangeX(self):
        self.x.append(4)

    def equals(self):
        print(self.x==self.y)

When I run this code the variables initialize as they should and such. If I run

f = Foo()
f.equals()

The output is True, which I can understand because both f.x and f.y hold the same value at this point. However, when I run

r = Foo()
r.ChangeX()
r.equals()

The output is still true. This confuses me. r.x and r.y plainly do not hold the same values anymore (printing them in sequence even gives different outputs), and yet Python seems to believe that the two variables equal each other.

I have a hunch that this has to do with the fact that I'm using a class; however I still dont know what exactly is going on here or how to "fix" it. Can someone explain?

Это было полезно?

Решение

self.x and self.y both reference the same list object in memory. Meaning, when you update one, the other will reflect the change.

You can see this behavior in the below demonstration:

>>> a = [1, 2, 3]
>>> b = a
>>>
>>> # The contents of a and b are the same
>>> a
[1, 2, 3]
>>> b
[1, 2, 3]
>>>
>>> # And their ids are the same
>>> id(a)
33908856
>>> id(b)
33908856
>>>
>>> a.append(4)
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
>>>

If you want to change this behavior, you could assign self.y to a shallow copy of self.x:

self.y = self.x[:]

See a demonstration below:

>>> a = [1,2,3]
>>> b = a[:]
>>>
>>> # The contents of a and b are the same
>>> a
[1, 2, 3]
>>> b
[1, 2, 3]
>>>
>>> # But their ids are different
>>> id(a)
33984680
>>> id(b)
33984960
>>>
>>> a.append(4)
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3]
>>>

Другие советы

You don't have two lists. You have a list x and a reference to list x called list y. When you modify your list x, the value behind the reference y is also modified. Read more about this here.

self.x and self.y refer to the same data. When you do

self.y = self.x

you bind both variables to the same array in memory.

Better to do this if you want them to be distinct

self.y = list(self.x)

As you can see, self.y = self.x is just assigning to y a reference to x:

class Foo:
    def __init__(self):
        self.x = [1,2,3]
        self.y = self.x

    def ChangeX(self):
        self.x.append(4)

    def equals(self):
        print(self.x==self.y)


f = Foo()
f.equals()
f.ChangeX()
f.equals()
print(f.x)
print(f.y)
#True
#True
#[1, 2, 3, 4]
#[1, 2, 3, 4]
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top