Как Python хранит дату и время внутри?

Я нашел _datetimemodule.c, который кажется подходящим файлом, но мне нужна небольшая помощь, поскольку C не является моей сильной стороной.

>>> import datetime
>>> import sys
>>> d = datetime.datetime.now()
>>> sys.getsizeof(d)
48
>>> d = datetime.datetime(2018, 12, 31, 23, 59, 59, 123)
>>> sys.getsizeof(d)
48

Таким образом, объект datetime, не знающий о часовом поясе, требует 48 байтов. Глядя на PyDateTime_DateTimeType, кажется, что это PyDateTime_DateType и PyDateTime_TimeType. Может еще и _PyDateTime_BaseTime?

Глядя на код, у меня создается впечатление, что для каждого поля в YYYY-mm-dd HH:MM:ss хранится один компонент, что означает:

  • Год: например, int (например, int16_t будет 16 бит)
  • Месяц: например, int8_t
  • день: например, int8_t
  • Час: например, int8_t
  • Минуты: например, int8_t
  • Второй: например, int8_t
  • Микросекунда: например, uint16_t

Но это будет 2 * 16 + 5 * 8 = 72 бит = 9 байт, а не 48 байт, как мне говорит Python.

Где мое предположение о внутренней структуре datetime неверно? Как это увидеть в коде?

(Я предполагаю, что это может отличаться между реализациями Python - если да, сосредоточьтесь на cPython)

Имейте в виду, что print(sys.getsizeof(d.year)) ; print(sys.getsizeof(d.month)) ; print(sys.getsizeof(d.day)) ; print(sys.getsizeof(d.hour)) ; print(sys.getsizeof(d.minute)) ; print(sys.getsizeof(d.second)) ; print(sys.getsizeof(d.microsecond)) печатает 28 семь раз, а 28 * 7 - это 196.

DeepSpace 16.09.2018 21:06

обратите внимание, что вы подсчитываете биты (2 int16_ts = 2 * 16), а не байты (int16_t = 2 байта). побайтно это 10 байт. но у объектов python есть накладные расходы, и минимальный размер кажется не менее 28 байтов, а иногда и больше, в зависимости от объекта. Я не проводил там столько расследования.

Corley Brigman 16.09.2018 21:11
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
2
927
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам не хватает ключевой части картины: фактических определений структуры datetime, которые лежат в Include/datetime.h. Там также есть важные комментарии. Вот некоторые ключевые выдержки:

/* Fields are packed into successive bytes, each viewed as unsigned and
 * big-endian, unless otherwise noted:
 *
 * byte offset
 *  0           year     2 bytes, 1-9999
 *  2           month    1 byte, 1-12
 *  3           day      1 byte, 1-31
 *  4           hour     1 byte, 0-23
 *  5           minute   1 byte, 0-59
 *  6           second   1 byte, 0-59
 *  7           usecond  3 bytes, 0-999999
 * 10
 */

...

/* # of bytes for year, month, day, hour, minute, second, and usecond. */
#define _PyDateTime_DATETIME_DATASIZE 10

...

/* The datetime and time types have hashcodes, and an optional tzinfo member,
 * present if and only if hastzinfo is true.
 */
#define _PyTZINFO_HEAD          \
    PyObject_HEAD               \
    Py_hash_t hashcode;         \
    char hastzinfo;             /* boolean flag */

...

/* All datetime objects are of PyDateTime_DateTimeType, but that can be
 * allocated in two ways too, just like for time objects above.  In addition,
 * the plain date type is a base class for datetime, so it must also have
 * a hastzinfo member (although it's unused there).
 */

...

#define _PyDateTime_DATETIMEHEAD        \
    _PyTZINFO_HEAD                      \
    unsigned char data[_PyDateTime_DATETIME_DATASIZE];

typedef struct
{
    _PyDateTime_DATETIMEHEAD
} _PyDateTime_BaseDateTime;     /* hastzinfo false */

typedef struct
{
    _PyDateTime_DATETIMEHEAD
    unsigned char fold;
    PyObject *tzinfo;
} PyDateTime_DateTime;          /* hastzinfo true */

48-байтовый счетчик, который вы видите, распределяется следующим образом:

  • 8-байтовый счетчик ссылок
  • 8-байтовый указатель типа
  • 8-байтовый кешированный хеш
  • 1-байтовый флаг hastzinfo
  • 7-байтовое заполнение
  • 10-байтовый char[10], упакованный вручную, содержащий данные даты и времени
  • 6-байтовое заполнение

Это, конечно, все детали реализации. Он может отличаться от другой реализации Python, или другой версии CPython, или 32-битной сборки CPython, или отладочной сборки CPython (в PyObject_HEAD есть дополнительные вещи, когда CPython скомпилирован с определенным Py_TRACE_REFS).

usecond: 3 byte может быть опечаткой? У какого типа 3 байта? Я видел только некоторые с 2 байтами, а некоторые с 4 байтами.

Martin Thoma 16.09.2018 22:41

@MartinThoma: байты данных datetime вручную упаковываются в char[10], поэтому нет необходимости в трехбайтовом типе.

user2357112 supports Monica 17.09.2018 00:48

Другие вопросы по теме