LINUX.ORG.RU

Кажется, я чего-то не понимаю

 ,


0

1

Подозреваю, что вопрос нубский, ибо не так давно начал изучать Python. Но всё равно причин данного поведения я не понимаю.

>>> class Number:
    nums = []
    flag = True

>>> a = Number()
>>> b = Number()
>>> a.nums += [1]
>>> b.nums
[1]
>>> a.flag = False
>>> b.flag
True
Но почему? Как сделать так, чтобы изменения nums в a не затрагивали nums в b? Ведь flag изменения не затрагивают.
Python 3.2.2, но то же самое и с 2.7.2

Deleted

>>> class Number:

nums = []

flag = True

здесь ты работаешь с переменными класса, а не обьекта => все обращения к этим переменным(в обьектах класса) будут глобальны для всех обьектов.

в твоем случае нужно явно инитить все переменные:

class test(): 
    def __init__(self):
        self.hash={}

dreamer ★★★★★
()
Ответ на: комментарий от dreamer

Да, помогло, спасибо. Кажется, я начинаю понимать.
Одно мне остаётся непонятным: почему это не касается int и bool внутри класса, но касается list и set?

Deleted
()
Ответ на: комментарий от Deleted

когда ты создаешь экземпляр класса, ему передаются в свойстве nums ссылка на список, а список это изменяемая структура в питоне. Поэтому все кто смотрит на эту ссылку будут видеть все изменения. Инты, булеаны и строки это неизменяемые «структуры», когда ты прибавляешь число или изменяешь строку, свойство объекта начинает смотреть в другое место - на новую строку(булеан, инт)

Zubchick
()
Ответ на: комментарий от Deleted

так устроен питон. В этом и отличие mutable типов от immutable

true_admin ★★★★★
()
>>> class Number:
    # nums и flag это (статические) члены класса,
    # они будут общими для всех экземпляров класса (и это в общем очевидно)
    nums = []
    flag = True
>>> a = Number()
>>> b = Number()
>>> a.nums is b.nums is Number.nums # a.nums и b.nums, a.flag и b.flag указывают не на атрибуты экземпляров a и b, а на члены класса-родителя; проверка "a.flag is b.flag is Number.flag" лишена смысла, поскольку True/False как булевые объекты уникальны и в проверке идентичности не нуждаются
True
>>> a.nums += [1] # изменяем изменяемый объект, на который указывает член класса Number (nums); операция "a.nums += [1]" для списков равнозначна операции "a.nums.extend([1])", которая не создаёт новый список, а расширяет старый переданным как аргумент списком
>>> Number.nums, a.nums, b.nums, Number.nums is a.nums is b.nums # как видно, атрибуты экземпляров по-прежнему ссылаются на член класса, который при этом изменился (что означает, что все созданные после этого экземпляры класса будут через атрибут nums ссылаться уже на список [1], а не [], как было ранее определено в объявлении класса)
([1], [1], [1], True)
>>> a.flag = False # здесь, что важно, мы переопределяем атрибут экземпляра "a" класса Number, это изменение не отразится ни на самом классе-родителе, ни на других экземплярах класса
>>> b.flag # b.flag по-прежнему "смотрит" на Number.flag
True
>>> Number.flag = False # переопределяем член класса и одновременно обновляем атрибуты всех экземпляров этого класса, для которых эти члены не переопределены
>>> b.flag # проверка
False
>>> 
Virtuos86 ★★★★★
()
Ответ на: комментарий от Deleted

А по какой причине экземпляру класса передаётся ссылка на список, а не копия этого списка?

Ему ничего не передаётся, так работает механизм разрешения имён. Если совсем просто, то сначала имя ищется в объекте инстанса и если его там нет - в объектах класса согласно иерархии классов (от самого верхнего класса вниз, называется MRO - атрибут __mro__ у каждого объекта класса). При

a.nums += [1]

меняешь атрибут объекта класса, а в случае

a.flag = False

создаёшь новый атрибут в объекте инстанса, сам атрибут объекта класса при этом остаётся каким был. В следующий раз, когда обращается снова к этому атрибуту инстанса a, он уже берётся из объекта инстанса, а не из объекта класса.

И свойство мутабельности объектов к этому не имеет никакого отношения. Просто в этих случаях разные операции, первая - операция над объектом, вторая - операция над слотом атрибута объекта.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Просто в этих случаях разные операции, первая - операция над объектом, вторая - операция над слотом атрибута объекта.

В этом месте немного наврал, в обеих операциях будет создан новый слот для атрибута в объекте инстанса. Да, список (list) для операции += вернёт свой же объект, число создаст новый объект и вернёт его.

В общем, основная фишка здесь это механизм поиска и создания атрибутов объектов и вторая - реализация операторов для объектов откуда и вытекает свойства мутабельности.

mashina ★★★★★
()
Ответ на: комментарий от Zubchick
class A(object):
    var = [0]

a = A()
b = A()

print a.var, b.var
a.var += [2]
A.var = [1]
print a.var, b.var

Отгадаешь выхлоп без интерпретатора?

anonymous
()
Ответ на: комментарий от Virtuos86

Блин, только сейчас понял длинный опус про разрешение имён из главы «Классы» официального python tutorial.

Спасибо.

yvv ★★☆
()
Ответ на: комментарий от anonymous

Я отгадал, пойду возьму с полки пирожок.

aidaho ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.