Изначально я задал этот вопрос в сиг-листе Python capi -:. Как передать аргументы в tp _new и tp _init из подтипов?
Я читаю Python PEP -253 о подтипах, и там есть много хороших рекомендаций о том, как структурировать типы, вызывать слоты tp_new
и tp_init
и т. д.
Но,в нем отсутствует важное примечание о передаче аргументов из подтипа в супертип. Судя по примечанию :
(XXX There should be a paragraph or two about argument passing here.)
, PEP -253 не закончен. Итак, я пытаюсь экстраполировать некоторые стратегии , хорошо известные из подтипов классов Python , особенно методы, при которых каждый уровень удаляет -аргументы и т. д.
Я ищу методы для достижения аналогичного эффекта, но с использованием простого Python C API(3.x):
class Shape:
def __init__(self, shapename, **kwds):
self.shapename = shapename
super().__init__(**kwds)
class ColoredShape(Shape):
def __init__(self, color, **kwds):
self.color = color
super().__init__(**kwds)
Что было бы эквивалентно в Python C API?
Как поступить в похожей ситуации, но с аргументами, характерными для производного класса, ожидаемыми в другом порядке? Это аргументы, указанные в конце кортежа args (или kwds
dict, я предполагаю, что принцип будет таким же ).
Вот некоторый (псевдо-)код, иллюстрирующий ситуацию:
class Base:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
class Derived(Base):
def __init__(self, x, y, a):
self.a = a
super().__init__(x, y, None):
Обратите внимание, если сначала ожидалось a
:
Derived.__init__(self, a, x, y)
это было бы похоже на ситуацию Shape
и ColoredShape
выше. Я полагаю, с ним также будет легче иметь дело.
Может ли кто-нибудь помочь выяснить недостающий комментарий XXX , упомянутый выше, и правильную технику передачи аргументов от подтипа до супертипа (s )при построении?
ОБНОВЛЕНИЕ 2012 -07 -17:
Вдохновленный ответом ecatmur ниже, я просмотрел исходники Python 3 и нашел defdict_init
конструктор объекта типа collections.defaultdict интересным. Тип является производным от PyDictObject
, а его конструктор принимает дополнительный аргумент default_factory
. Подпись конструктора в классе Python такова:
class collections.defaultdict([default_factory[,...]])
Теперь вот как default_factory
отделяется от исходного кортежа args
, поэтому остальные аргументы перенаправляются в tp_init
базового типа, этоPyDictObject
:
int result;
PyObject *newargs;
Py_ssize_t n = PyTuple_GET_SIZE(args);
...
newargs = PySequence_GetSlice(args, 1, n);
...
result = PyDict_Type.tp_init(self, newargs, kwds);
Обратите внимание, что в этом фрагменте присутствует только соответствующая часть функции defdict_init
.