Почему два списка с одинаковыми данными показывают разные адреса памяти в Python, когда мы применяем оператор идентификации?

#python #python-3.x #list #data-structures #memory-management

Вопрос:

У меня есть два списка.

 list1=["divyansh","jain","python"]
list2=["divyansh","jain","python"]
 

Оба списка содержат точно такие же данные.

Но когда мы применяем is оператор идентификации, он выдает нам ложь, а также адрес памяти другой.

Я знаю, что в python все является объектом. Если я объявлю другую переменную с тем же значением данных, обе переменные будут указывать на один и тот же объект. Тогда почему это не работает в случае типа данных списка.

Я знаю, что python выделяет объект по умолчанию во время выполнения для int значений в диапазоне от 0 до 255, boolean значений и пустых string .

Почему list2 указывает на какой-то другой адрес памяти, когда list1 был создан в первую очередь с точно такими же значениями?

Код :

 x=300
y=300
print("Memory Address of variable x is : ",id(x))
print("Memory Address of variable y is : ",id(y))
print(x is y)
print(x is not y)
list1=["divyansh","jain","python"]
list2=["divyansh","jain","python"]
print("Memory Address of variable list1 is : ",id(list1))
print("Memory Address of variable list2 is : ",id(list2))
print(list1 is list2)
print(list1 is not list2)

Output : 
Memory Address of variable x is :  140185049313168
Memory Address of variable y is :  140185049313168
True
False
Memory Address of variable list1 is :  140185048064584
Memory Address of variable list2 is :  140185048053000
False
True
 

Создание объекта является более трудоемкой и дорогостоящей операцией, чем его поиск и присвоение ему одного и того же адреса памяти. Я понимаю , что для изменяемых объектов это невозможно, в будущем, если мы изменим list2, данные list1 будут изменены, и по этой причине он создал объект diff. Но для фундаментальных неизменяемых типов данных,таких как int,float,str,он выделяет ту же память,но в случае неизменяемых типов данных,таких как байты, кортеж, набор данных, комплекс, диапазон, он не выделяет ту же память, хотя имеет то же значение данных.

Пример других типов данных :

 tuple1=("divyansh","jain","python")
tuple2=("divyansh","jain","python")
print("Memory Address of variable tuple1 is : ",id(tuple1))
print("Memory Address of variable tuple2 is : ",id(tuple2))
print(tuple1 is tuple2)
print(tuple1 is not tuple2)

bytes1=[1,2,3]
bytes2=[1,2,3]
b1=bytes(bytes1)
b2=bytes(bytes2)
print(type(b1),type(b2))
print(id(b1))
print(id(b2))
print(bytes1 is bytes2)

a=10.5
b=10.5
print(type(a),type(b))
print(id(a))
print(id(b))
print(a is b)

c1=10 20j
c2=10 20j
print(type(c1),type(c2))
print(id(c1))
print(id(c2))
print(c1 is c2)

s1="Dj"
s2="Dj"
print(type(s1),type(s2))
print(id(s1))
print(id(s2))
print(s1 is s2)


f1=frozenset({"Dj"})
f2=frozenset({"Dj"})
print(type(f1),type(f2))
print(id(f1))
print(id(f2))
print(f1 is f2)

r1=range(10)
r2=range(10)
print(type(r1),type(r2))
print(id(r1))
print(id(r2))
print(r1 is r2)

Memory Address of variable tuple1 is : 140088826761792
Memory Address of variable tuple2 is : 140088826762008
False
True
<class 'bytes'> <class 'bytes'>
140088827913280
140088827388192
False
<class 'float'> <class 'float'>
140088827982304
140088827982304
True
<class 'complex'> <class 'complex'>
140088827402864
140088827402896
False
<class 'str'> <class 'str'>
140088826759184
140088826759184
True
<class 'frozenset'> <class 'frozenset'>
140088827366088
140088827365640
False
<class 'range'> <class 'range'>
140088846540448
140088827189840
False
 

Комментарии:

1. Python кэширует небольшие целые числа, но не маленькие списки. Это все.

2. Чтобы ответить на ваш вопрос, потому что это два разных объекта списка . Почему вы ожидаете, что у них будет один и тот же идентификатор?

3. «Если я объявлю другую переменную с тем же значением данных, обе переменные будут указывать на один и тот же объект». Нет, это совсем не так. Как доказывает этот простой пример.

4. По сути, ваше предположение о том, что неизменяемые объекты с одинаковым значением всегда имеют одинаковую идентичность, просто неверно .

5. То, на что вы смотрите, — это методы оптимизации для работы с примитивными типами данных. Список, кортеж, диктант, набор и т. Д. Являются составными типами данных, и это просто того не стоит: сначала вам нужно создать их полную форму в памяти, а затем вы можете проверить, есть ли она у вас где-то еще.

Ответ №1:

В стандартном случае объектного программирования: когда вы создаете новый объект, язык/компьютер зарезервирует для него новое пространство памяти и адрес.

В Python, когда вы создаете такие объекты, как список/контейнеры, которые являются изменяемыми объектами, каждый из них имеет свой собственный адрес памяти. Таким образом, вы можете работать с ними и изменять один, не изменяя второй. Это необходимо, если бы адрес был одинаковым, это был бы один и тот же объект с двумя именами/указателями.

Это необходимо для обработки изменений списка 1 и списка 2 без изменения другого. Поскольку списки являются объектами мутабе.

Чтобы проверить идентичность содержимого, вы должны проверить каждый элемент в списках. В Python использование оператора ‘==’ работает для сравнения содержимого с числами, списками, кортежами,…

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

Этот выбор оптимизации был сделан потому, что создание нового объекта number каждый раз отнимало бы много времени и памяти. А также количество выделенной/освобожденной памяти также было бы слишком большим.

Комментарии:

1. Но тогда почему это не так в случае с кортежем ? Кортеж неизменен. tuple1=(«дивьянш»,»джейн»,»питон») tuple2=(«дивьянш»,»джейн»,»питон») печать(«Адрес памяти переменной tuple1 : «,идентификатор(tuple1)) печать(«Адрес памяти переменной tuple2 : «,идентификатор(tuple2)) печать(tuple1-это tuple2) печать(tuple1-это tuple2) Печать (tuple1-это не tuple2) Адрес памяти переменной tuple1 : 140228882485824 Адрес памяти переменной tuple2 : 140228882486040 Ложь Истина

2. Это не концепция, а произвольный выбор языковых программистов для реализации и оптимизации, и вы не можете полагаться на это. Поскольку списки изменчивы, в памяти обязательно должен быть другой объект и, следовательно, другой адрес, здесь выбора нет. Возможно, вы можете найти объяснение/текст в PEPs Python здесь: python.org/dev/peps/#introduction

3. @DivyanshJain вы всегда должны предполагать, что создан новый объект . Для неизменяемых объектов среда выполнения Python оставляет за собой право оптимизировать это. Это деталь реализации . Это не особенность языка, не часть стандарта. На самом деле, для случаев None , True , и False они являются гарантированными синглетами на языке, но это не относится ко всем неизменяемым объектам вообще. Предпосылка о том, что «если объект неизменен и имеет одинаковое значение, то это должен быть один и тот же объект», является просто ложной предпосылкой

4. @DivyanshJain также обратите внимание, что иногда tuple объекты кэшируются оптимизатором глазков. Но опять же, вам никогда не следует полагаться на это.

5. «Именно в этом я и сомневаюсь . Создание объекта является более трудоемкой и дорогостоящей операцией, чем его поиск и присвоение ему одного и того же адреса памяти». Это вообще абсолютно неверно.