Парадокс курицы или яйца с типом и объектом в Python - PullRequest
0 голосов
/ 08 июня 2019

Я вспомнил, что узнал, что type является его собственным экземпляром и что все классы нового стиля наследуются от object, поэтому я начал возиться:

issubclass(type, object) # True
issubclass(object, type) # False
# issubclass(cls, cls) is always True
type(type) is type # True
type(object) is type # True

Подводя итог, можно сказать, что type, как и любой класс нового стиля, является подклассом object, и, как и любой класс, type и object являются экземплярами type. Вот удобная картинка:

Picture of relationship between type and object in Python

Большой отказ от ответственности за то, что я не программист и мало знаю о базовой механике Python, так что терпите меня, если я говорю глупо. Обычно класс должен быть создан до его экземпляров. Тем не менее, суперкласс обычно должен быть создан до его подкласса. Применение этих общих правил Python к type и object создает очевидный парадокс с куриным яйцом.

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

Ответы [ 2 ]

2 голосов
/ 08 июня 2019

С точки зрения семантики языка, type и object существуют, полностью инициализированные, с момента запуска программы.Что бы реализация ни делала, чтобы привести вещи в это состояние, не обязательно должно следовать правилам того, что реализация позволяет you .

С точки зрения реализации CPython как type, так иobject статически размещаются на уровне C, и ни один из них не создается первым.Вы можете увидеть определения переменных в Objects/typeobject.c. Здесь object:

PyTypeObject PyBaseObject_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "object",                                   /* tp_name */
    sizeof(PyObject),                           /* tp_basicsize */
    0,                                          /* tp_itemsize */
    object_dealloc,                             /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    object_repr,                                /* tp_repr */
    ...
};

и здесь type:

PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                                     /* tp_name */
    sizeof(PyHeapTypeObject),                   /* tp_basicsize */
    sizeof(PyMemberDef),                        /* tp_itemsize */
    (destructor)type_dealloc,                   /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    (reprfunc)type_repr,                        /* tp_repr */
    ...
};

Когда начинается инициализация интерпретатора, оба typeobject находятся в полуинициализированном состоянии, а функция PyType_Ready отвечает за завершение их инициализации.Указатели типов устанавливаются в определениях переменных, но установка указателей суперкласса является частью работы PyType_Ready, и множество других инициализаций должны обрабатываться PyType_Ready - например, типы не имеют__dict__ пока.

Кстати, используя некоторые странные метаклассы и тот факт, что Python позволяет переназначать __class__ для экземпляров пользовательских классов, мы можем настроить наши собственные классы A и B, где B является подклассом A, а оба A и B являются экземплярами B, очень похоже на ситуацию с object и type.Это не похоже на то, как на самом деле создаются object и type, хотя:

class DummyMeta(type):
    pass

class A(type, metaclass=DummyMeta):
    pass

class B(A):
    pass

B.__class__ = B
A.__class__ = B

print(isinstance(A, B))
print(isinstance(B, B))
print(issubclass(B, A))

Вывод:

True
True
True
1 голос
/ 08 июня 2019

В Python все является объектом:

  • 7 является объектом типа int.
  • 'foo' - это объект типа str.
  • None является объектом типа NoneType.
  • Если вы определяете класс class Foo: pass, тогда Foo является объектом типа class. И любой объект Foo(), который вы создаете из этого класса, является объектом типа Foo.
  • Если вы определяете функцию как def f(x): pass,, то эта функция сама является объектом.

Каждый объект имеет тип. Но что это за тип? Это верно - даже сами типы являются объектами типа type.

issubclass(type, object) # True
issubclass(object, type) # False

Каждый класс является подклассом object по определению. Класс object не является подклассом чего-либо; это корень всей "объектности". Отсюда следует, что isinstance(o, object) всегда возвращает True.

type(type) is type # True
type(object) is type # True

Мы знаем, что все в python является экземпляром object. Но как насчет самого класса object? Это тоже объект. Что за объект? object - это тип, такой же как int, str или function. Таким образом, тип object равен type. Однако любой экземпляр класса object является не типом, а просто объектом:

type(object()) is object # True

Таким образом, все является объектом, даже типы других объектов.

Чтобы не ответить на вопрос «что на первом месте», это не имеет значения; в любом случае эти вещи являются абстракциями, и поэтому вы можете создать язык с любой семантикой, которую вы хотите определить, и в «циклах» нет ничего плохого.

Чтобы дать более конкретный ответ, если вы заинтересованы в реализации, это выглядит как typedef для c-level PyObject s (которые становятся object) в исходном коде для CPython здесь и сравните с typedef для PyTypeObject в том же файле.

Редактировать: другой ответ лучше объясняет реализацию CPython.

...