Почему id ({}) == id ({}) и id ([]) == id ([]) в CPython? - PullRequest
24 голосов
/ 07 октября 2010

Почему CPython (без понятия о других реализациях Python) имеет следующее поведение?

tuple1 = ()
tuple2 = ()                                                                                                   
dict1 = {}
dict2 = {}
list1 = []
list2 = []
# makes sense, tuples are immutable
assert(id(tuple1) == id(tuple2))
# also makes sense dicts are mutable
assert(id(dict1) != id(dict2))
# lists are mutable too
assert(id(list1) != id(list2))
assert(id(()) == id(()))
# why no assertion error on this?
assert(id({}) == id({}))
# or this?
assert(id([]) == id([]))

У меня есть несколько идей, почему он может , но не могу найти конкретную причину.

EDIT

Чтобы еще раз доказать точку зрения Гленна и Томаса:

[1] id([])
4330909912
[2] x = []
[3] id(x)
4330909912
[4] id([])
4334243440

Ответы [ 4 ]

41 голосов
/ 07 октября 2010

Когда вы вызываете id({}), Python создает dict и передает его в функцию id. Функция id берет свой идентификатор (место в памяти) и выбрасывает dict. Дикт уничтожен. Когда вы делаете это дважды в быстрой последовательности (без создания каких-либо других диктовок за это время), диктат, создаваемый Python во второй раз, использует тот же блок памяти, что и в первый раз. (Распределитель памяти CPython делает это намного более вероятным, чем кажется.) Поскольку (в CPython) id использует расположение памяти в качестве идентификатора объекта, идентификатор двух объектов одинаков. Этого, очевидно, не произойдет, если вы присваиваете dict переменной, а затем получаете ее id(), потому что дикты живы в то же время , поэтому их id должно быть другим.

Изменчивость не входит непосредственно в игру, но кодирование объектов кода кортежей и строк делает. В одном и том же объекте кода (тело функции или класса или тело модуля) будут повторно использоваться одни и те же литералы (целые числа, строки и определенные кортежи). Изменяемые объекты никогда не могут быть использованы повторно, они всегда создаются во время выполнения.

Короче говоря, идентификатор объекта уникален только для времени жизни объекта . После того, как объект уничтожен или перед его созданием, что-то еще может иметь такой же идентификатор.

36 голосов
/ 07 октября 2010

CPython - это сборщик мусора, как только они выходят из области видимости, поэтому второй [] создается после того, как первый [] собран.Таким образом, большую часть времени он оказывается в одной и той же области памяти.

Это показывает, что происходит очень четко (выходные данные, вероятно, будут другими в других реализациях Python):

class A(object):
    def __init__(self): print "a",
    def __del__(self): print "b",

# a a b b False
print A() is A()
# a b a b True
print id(A()) == id(A())
0 голосов
/ 07 октября 2010

Оператор == в списках и списках не сравнивает идентификаторы объектов, чтобы определить, являются ли они одним и тем же объектом - для этого используйте obj1 is obj2.

Вместо этого оператор == сравнивает членов спискадиктовать, если они одинаковы.

0 голосов
/ 07 октября 2010

в Jython это работает не так ...

>>> id({})
1
>>> id([])
2

Может ли происходить оптимизация, когда обычно используемые (то есть пустые) контейнеры "интернируются" для экономии затрат на выделение?

Это (в CPython) предлагает не:

>>> def mutateid(obj):
...   obj.append('x')
...   print obj
...   print id(obj)
... 
>>> mutateid([])
['x']
4299590472
>>> id([])
4299590472
>>> 
...