#python #python-datamodel
#python #python-datamodel
Вопрос:
только что столкнулся с проблемой при создании подкласса dict «type». Я переопределил __iter__ method и ожидал, что это повлияет на другие методы, такие как iterkeys, keys и т.д. Потому что я полагал, что они вызывают __iter__ method для получения значений, но, похоже, они реализованы независимо, и я должен переопределить их все.
Является ли это ошибкой или намерением, чтобы они не использовали другие методы и извлекали значения отдельно?
Я не нашел в стандартной документации Python описания зависимости вызовов между методами стандартных классов. Это было бы удобно для подсчета работы и для ориентации, какие методы требуется переопределить для правильного поведения. Существует ли какая-либо дополнительная документация о внутренних элементах базовых типов / классов python?
Ответ №1:
Создайте подкласс Mapping
или MuteableMapping
из модуля коллекций вместо dict
, и вы получите все эти методы бесплатно.
Вот пример минимального сопоставления и некоторые из методов, которые вы получаете бесплатно:
import collections
class MinimalMapping(collections.Mapping):
def __init__(self, *items ):
self.elements = dict(items)
def __getitem__(self, key):
return self.elements[key]
def __len__(self):
return len(self.elements)
def __iter__(self):
return iter(self.elements)
t = MinimalMapping()
print (t.iteritems, t.keys, t.itervalues, t.get)
Для создания подкласса любого из встроенных контейнеров вы всегда должны использовать соответствующий базовый класс из модуля collections.
Комментарии:
1. Спасибо за подсказку. Я упомянул dict в качестве примера. Я ищу более общие принципы создания подклассов в Python.
2. @David Unric: Это является общим принципом..
dict
etc должны выполняться как можно быстрее, а не быть легко расширяемыми — для этого предназначены базовые классы в модуле collections.3. Скорость может быть одной из причин для создания подкласса
dict
вместоcollections.Mapping
. Излишне говорить, что я не согласен с вашим утверждением о том, что всегда создается подкласс изcollections
базового класса, а не встроенных. Одной из причин введения новой объектной модели в Python 2.2 было именно то, что вы могли создавать подклассы встроенных функций.4. 1 за чтение мыслей: хотя это вообще не отвечает на письменный вопрос, автор сообщения выбрал его в качестве ответа!
Ответ №2:
Если это не указано в документации, это зависит от реализации. Другие реализации, для реализации которых CPython может повторно использовать iter
метод iterkeys
, и другие. Я бы не считал это ошибкой, а просто небольшой свободой для разработчиков.
Я подозреваю, что существует фактор производительности при независимой реализации методов, тем более что словари так широко используются в Python.
Итак, в принципе, вы должны их реализовать.
Комментарии:
1. Да, я предполагал, что это способ реализовать их все. Может ли кто-нибудь еще подтвердить, что это не ошибка или функция, удаленная в Pyton 3.x
Ответ №3:
Вы знаете поговорку: «Вы знаете, что происходит, когда вы предполагаете». 🙂
Они официально не документируют этот материал, потому что могут решить изменить его в будущем. Любая неофициальная документация, которую вы можете найти, просто документирует текущее поведение одной реализации Python, и полагаться на нее приведет к тому, что ваш код будет очень, очень хрупким.
Когда существует официальная документация по специальным методам, она, как правило, описывает поведение интерпретатора по отношению к вашим собственным классам, например, использование, __len__()
когда __nonzero__()
это не реализовано, или требуется только __lt()__
для сортировки.
Поскольку Python использует утиный ввод, вам обычно не нужно наследовать от встроенного класса, чтобы ваш собственный класс действовал как один. Итак, вы могли бы пересмотреть, действительно ли создание подклассов dict
— это то, что вы хотите сделать. Вы можете выбрать другой класс, например, что-то из collections
модуля, или инкапсулировать, а не наследовать. ( UserString
Класс использует инкапсуляцию.) Или просто начать с нуля.
Ответ №4:
Вместо создания подклассов dict
вы могли бы вместо этого просто создать make свой собственный класс, который имеет именно те свойства, которые вы хотите, без особых проблем. Вот сообщение в блоге с примером того, как это сделать. __str__()
Метод в нем не самый лучший, но это легко исправимо, остальные предоставляют функциональность, которую вы ищете.