Я нашел _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 хранится один компонент, что означает:
int16_t будет 16 бит)int8_tint8_tint8_tint8_tint8_tuint16_tНо это будет 2 * 16 + 5 * 8 = 72 бит = 9 байт, а не 48 байт, как мне говорит Python.
Где мое предположение о внутренней структуре datetime неверно? Как это увидеть в коде?
(Я предполагаю, что это может отличаться между реализациями Python - если да, сосредоточьтесь на cPython)
обратите внимание, что вы подсчитываете биты (2 int16_ts = 2 * 16), а не байты (int16_t = 2 байта). побайтно это 10 байт. но у объектов python есть накладные расходы, и минимальный размер кажется не менее 28 байтов, а иногда и больше, в зависимости от объекта. Я не проводил там столько расследования.






Вам не хватает ключевой части картины: фактических определений структуры 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-байтовый счетчик, который вы видите, распределяется следующим образом:
char[10], упакованный вручную, содержащий данные даты и времениЭто, конечно, все детали реализации. Он может отличаться от другой реализации Python, или другой версии CPython, или 32-битной сборки CPython, или отладочной сборки CPython (в PyObject_HEAD есть дополнительные вещи, когда CPython скомпилирован с определенным Py_TRACE_REFS).
usecond: 3 byte может быть опечаткой? У какого типа 3 байта? Я видел только некоторые с 2 байтами, а некоторые с 4 байтами.
@MartinThoma: байты данных datetime вручную упаковываются в char[10], поэтому нет необходимости в трехбайтовом типе.
Имейте в виду, что
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.