Разница между переменными экземпляра и атрибутами в Python?

1

Таким образом, документы python для написания расширений говорят следующее:

"Мы хотим раскрывать наши переменные экземпляра в качестве атрибутов. Существует несколько способов сделать это. Самый простой способ - определить определения членов:

static PyMemberDef Noddy_members[] = {
    {"first", T_OBJECT_EX, offsetof(Noddy, first), 0,
     "first name"},
    {"last", T_OBJECT_EX, offsetof(Noddy, last), 0,
     "last name"},
    {"number", T_INT, offsetof(Noddy, number), 0,
     "noddy number"},
    {NULL}  /* Sentinel */
};

и поместите определения в слот tp_members:

Noddy_members,             /* tp_members */"

Однако мы уже поместили переменные экземпляра в структуру Noddy:

 typedef struct {
    PyObject_HEAD
    PyObject *first;
    PyObject *last;
    int number;
} Noddy;

поэтому мой вопрос в том, почему мы помещаем их в оба места. Мое впечатление, что это потому, что мы хотим, чтобы и тип, и экземпляр имели их, чтобы мы сохраняли значения типов после обновления экземпляра. Но если это так, как обновляется значение экземпляра, если мы изменим атрибут класса? как это:

>>> class foo(object): x = 4
...
>>> f = foo()
>>> f.x
4
>>> foo.x = 5
>>> f.x
5
Теги:
cython
python-c-api
python-c-extension

2 ответа

1
Лучший ответ

Итак, я сделал свое исследование и да переменные экземпляра и атрибуты разные, и это потому, что классы и классы классов имеют отдельные словари. Как сказано в документации:

Экземпляр класса создается путем вызова объекта класса (см. Выше). Экземпляр класса имеет пространство имен, реализованное в качестве словаря, который является первым местом, в котором выполняется поиск ссылок на атрибуты. Когда атрибут не найден там, а класс экземпляров имеет атрибут с таким именем, поиск продолжается с атрибутами класса.

Таким образом, в основном структура Noddy содержит переменные экземпляра. Элементы Noddy_members содержат атрибуты. Более того:

Назначения и удаления атрибутов обновляют словарь экземпляров, а не словарь классов. Если класс имеет метод setattr() или delattr(), он вызывается вместо непосредственного обновления словаря экземпляра.

Также:

Если обнаружен атрибут класса, который является определяемым пользователем объектом функции или несвязанным определяемым пользователем объектом метода, ассоциированным классом которого является класс (называет его C) экземпляра, для которого была инициирована ссылка атрибута, или одна из ее баз, преобразуется в связанный пользовательский объект метода, чей атрибут im_class является C и чей im_self является экземпляром. Статический метод и объекты метода класса также преобразуются, как если бы они были извлечены из класса C; см. выше в разделе "Классы". См. Раздел "Реализация дескрипторов" для другого способа, в котором атрибуты класса, извлеченного через его экземпляры, могут отличаться от объектов, фактически хранящихся в классах dict. Если атрибут класса не найден, а класс объектов имеет метод getattr(), который вызывается для удовлетворения поиска.

2

Написание расширения C - сложный процесс, потому что вам нужно написать C-код, и вы должны предоставить достаточную информацию Python, чтобы он мог управлять вашими данными C, как если бы это были данные Python. Вы должны упомянуть членов структуры дважды: один раз, когда компилятор C знает, как сделать структуру, а затем снова, чтобы Python знал, где находятся данные и что он называется.

C не имеет возможности интроспекции, поэтому вы не можете (например) получить список членов структуры во время выполнения. Массив PyMemberDef предоставляет эту информацию.

  • 1
    Другими словами, Python не имеет возможности заглядывать в ваш исходный код на C и видеть имена и типы членов вашей struct . Эта информация обычно даже не существует в скомпилированном коде, поэтому вы должны поместить ее туда, чтобы Python имел к ней доступ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню