Список как атрибут класса - PullRequest
       1

Список как атрибут класса

1 голос
/ 08 октября 2019

Я не до конца понимаю, в чем разница целочисленного или списка атрибутов класса в следующем примере:

class MyClass(object):

    a = [1]
    b = 1

    def __init__(self):
        print(self.a, id(MyClass.a))
        print(self.b, id(MyClass.b))

    def modify(self):
        self.a.append(2)
        print("modfied list attribute:", MyClass.a, id(MyClass.a))
        print("modfied listattribute:", self.a, id(self.a))

        self.b += 1
        print("modfied int attribute:", MyClass.b, id(MyClass.b))
        print("modfied int attribute:", self.b, id(self.b))

x = MyClass()
x.modify()
y = MyClass()

В выводе этого примера видно, что если я изменю список водин экземпляр (x), фактический атрибут в MyClass изменен. Однако целое число при изменении в одном экземпляре остается для класса тем же. Я предполагаю, что это связано с особенностями списка, то есть идентификатором остается, если к нему добавляется какое-либо значение.

Может ли кто-нибудь дать мне краткое объяснение в двух словах, какова основная причина такого поведения

Ответы [ 2 ]

3 голосов
/ 08 октября 2019

int значения неизменны. Вы не изменили существующее int, но заменили self.b на другое int значение.

list значения являются изменяемыми,и list.append изменяет экземпляр, который его вызывает. self.a изменяется на месте без замены существующего списка новым.

По сути, вы не можете предсказать поведение +=, не зная тип значения, использующего его. В b = 0; b += 1, b относится к новому экземпляру int. Но в b = []; b += [2,3] существующий список расширяется (как если бы вы звонили b.extend([2,3])).

0 голосов
/ 08 октября 2019

Посмотрите, как вы можете сделать это визуально с помощью оператора is (НЕ с ==):

class MyClass(object):

    a = [1]
    b = 1

    def __init__(self):
        print(self.a, id(MyClass.a))
        print(self.b, id(MyClass.b))

    def modify(self):
        self.a.append(2)
        print("modfied list attribute:", MyClass.a, id(MyClass.a))
        print("modfied listattribute:", self.a, id(self.a))

        self.b += 1
        print("modfied int attribute:", MyClass.b, id(MyClass.b))
        print("modfied int attribute:", self.b, id(self.b))

x = MyClass()
y = MyClass()
print(x.a is y.a)  # True
print(x.b is y.b)  # True

x.modify()

print(x.a is y.a)  # True
print(x.b is y.b)  # Falseclass MyClass(object):

    a = [1]
    b = 1

    def __init__(self):
        print(self.a, id(MyClass.a))
        print(self.b, id(MyClass.b))

    def modify(self):
        self.a.append(2)
        print("modfied list attribute:", MyClass.a, id(MyClass.a))
        print("modfied listattribute:", self.a, id(self.a))

        self.b += 1
        print("modfied int attribute:", MyClass.b, id(MyClass.b))
        print("modfied int attribute:", self.b, id(self.b))

x = MyClass()
y = MyClass()

# Before changing something a and b is a reference to the same object
print(x.a is y.a)  # True
print(x.b is y.b)  # True

x.modify()

# After that only x.b is a reference to a new object
# you accessed the list object that is shared and append a value
print(x.a is y.a)  # True
print(x.b is y.b)  # False

# If you would give x.a a new list it would look like this
x.a = []
print(x.a is y.a)  # False
print(x.b is y.b)  # False
# x.a is now not the same list as y.a

Если у вас нет причин использовать a и b в качестве атрибута класса, я бы посоветовал вам сделать этоатрибуты экземпляра:

class MyClass(object):

    def __init__(self):
        self.a = [1]
        self.b = 1
        print(self.a, id(self.a))
        print(self.b, id(self.b))

    def modify(self):
        self.a.append(2)
        print("modfied list attribute:", self.a, id(self.a))
        print("modfied listattribute:", self.a, id(self.a))

        self.b += 1
        print("modfied int attribute:", self.b, id(self.b))
        print("modfied int attribute:", self.b, id(self.b))

x = MyClass()
y = MyClass()
print(x.a is y.a)  # False
print(x.b is y.b)  # False

x.modify()

print(x.a is y.a)  # False
print(x.b is y.b)  # False


x.a = []
print(x.a is y.a)  # False
print(x.b is y.b)  # False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...