В MySQL есть два типа кавычек:
'
для включения строковых литералов `
для включения идентификаторов, таких как имена таблиц и столбцов И тогда есть "
, который является частным случаем. Он может быть использован для one вышеупомянутых целей за раз в зависимости от сервера MySQL sql_mode
:
"
может использоваться для вложения строковых литералов точно так же, как '
ANSI_QUOTES
символ "
может использоваться для заключите идентификаторы так же, как `
SELECT "column" FROM table WHERE foo = "bar"
Запрос будет выбирать строковый литерал "column"
, где column foo
равен строке "bar"
В запросе будет выбран столбец column
где столбец foo
равен столбцу bar
"
, чтобы ваш код не зависел от SQL mode id
объекта гарантированно будет уникальным во время жизни этого объекта , а не на протяжении всего времени жизни программы. Два созданных вами объекта someClass
существуют только в течение времени вызова print
- после этого они доступны для сбора мусора (и в CPython немедленно освобождаются). Поскольку их время жизни не перекрывается, для них действительно существует общий идентификатор.
В этом случае он также невосстанавливается из-за комбинации двух деталей реализации CPython: во-первых, сбор мусора путем подсчета ссылок (с некоторой дополнительной магией, чтобы избежать проблем с циклическими ссылками), а во-вторых, объект id
объекта связан со значением базового указателя для переменной (т. е. местоположения ее памяти). Итак, первый объект, который был последним выделенным объектом, сразу освобождается - не удивительно, что выделенный [ следующий объект будет находиться в одном и том же месте (хотя это потенциально также зависит от сведения о том, как был скомпонован переводчик).
Если вы полагаетесь на несколько объектов, имеющих разные id
s, вы можете держать их вокруг - скажем, в списке, чтобы их время жизни перекрывалось. В противном случае вы можете реализовать идентификатор класса, который имеет разные гарантии - например:
class SomeClass:
next_id = 0
def __init__(self):
self.id = SomeClass.nextid
SomeClass.nextid += 1
Если вы прочитали документацию для id
, в ней говорится:
Вернуть «идентификатор» объекта. Это целое число, которое гарантировано будет уникальным и постоянным для этого объекта в течение его жизни. Два объекта с неперекрывающимися временами жизни могут иметь одинаковое значение
blockquote>id()
.И это именно то, что происходит: у вас есть два объекта с неперекрывающимися сроками службы, потому что первый из них уже вышел
Но не верьте, что это будет всегда . Особенно, если вам нужно иметь дело с другими реализациями Python или с более сложными классами. Все, что говорит язык, состоит в том, что эти два объекта могут иметь одинаковое значение
id()
, а не то, что они будут . И тот факт, что они делают , зависит от двух деталей реализации:
- Сборщик мусора должен очистить первый объект, прежде чем ваш код даже начнет выделять второй объект- который, как гарантируется, произойдет с CPython или любой другой реализацией пересчета (когда нет круговых ссылок), но довольно маловероятен с коллективным сборщиком мусора, как в Jython или IronPython.
- Распределитель под крышками имеет чтобы иметь очень сильное предпочтение повторного использования недавно освобожденных объектов того же типа. Это справедливо в CPython, который имеет несколько уровней фантастических распределителей поверх базового C
malloc
, но большинство других реализаций намного больше уходят в основную виртуальную машину.
Последнее: факт, что
object.__repr__
имеет подстроку, которая оказывается такой же, какid
как шестнадцатеричное число, является всего лишь артефактом реализации CPython, который нигде не гарантируется. Согласно docs :Если это вообще возможно, это должно выглядеть как действительное выражение Python, которое может быть использовано для воссоздания объекта с тем же значением (с учетом соответствующая среда). Если это невозможно, должна быть возвращена строка формы
blockquote><...some useful description…>
.Тот факт, что CPython
object
, кажется, помещаетhex(id(self))
(фактически, я считаю, что он делает эквивалентsprintf
, указав его указатель на%p
, но поскольку CPythonid
просто возвращает тот же самый указатель, который был добавлен кlong
, который заканчивается тем же самым) нигде не гарантируется. Даже если это было верно, так как ... доobject
даже существовало в начале 2.x дней. Вы можете полагаться на него для такого простого простого «что здесь происходит» отладки в интерактивном приглашении, но не пытайтесь использовать его за его пределами.
Пример, когда место памяти (и id) не освобождено:
print([someClass() for i in range(10)])
Теперь идентификаторы уникальны.
Он освобождает первый экземпляр, поскольку он не был сохранен, тогда, поскольку между тем ничего не случилось с памятью, он создает второй раз в том же месте.
Я чувствую здесь более глубокую проблему. Вы не должны полагаться на id
, чтобы отслеживать уникальные экземпляры на протяжении всей вашей программы. Вы должны просто увидеть его как не гарантированный индикатор местоположения памяти в течение всего экземпляра объекта. Если вы сразу создаете и освобождаете экземпляры, вы можете очень хорошо создавать последовательные экземпляры в том же месте памяти.
Возможно, вам нужно отслеживать статический счетчик класса, который присваивает каждому новому экземпляру уникальный идентификатор, и увеличивает статический счетчик класса для следующего экземпляра.
Попробуйте это, попробуйте вызвать следующее:
a = someClass()
for i in range(0,44):
print(someClass())
print(a)
Вы увидите что-то другое. Зачем? Причина того, что память, выпущенная первым объектом в цикле «foo», была повторно использована. С другой стороны, a
не используется повторно, поскольку сохраняется.