Класс Python, доступный итератором и индексом

Может быть вопрос n00b, но в настоящее время у меня есть класс, который реализует итератор, поэтому я могу сделать что-то вроде

for i in class(): 

но я хочу иметь доступ к классу по индексу, а также

 class()[1] 

Как я могу это сделать?

Благодаря!

  • HTML-теги для choicefield в Django
  • Итерировать вложенный словарь в Python
  • Как я могу использовать функции mongo в pymongo?
  • перечисление элементов во вложенных списках по диагонали
  • как я могу полностью контролировать свою трехмерную человеческую модель?
  • Измерьте размер объекта точно в Python - Sys.GetSizeOf не работает
  • Доступ к пакетам samba с gio в python
  • Как вы получаете заголовки по умолчанию в запросе urllib2?
  • 2 Solutions collect form web for “Класс Python, доступный итератором и индексом”

    Внедрите __iter__() и __getitem__() и другие.

    Текущий принятый ответ от @Ignacio Vazquez-Abrams достаточно. Однако другие, интересующиеся этим вопросом, могут захотеть наследовать свой класс из абстрактного базового класса (например, найденного в стандартном модуле collections.abc ). Это делает несколько вещей (возможно, есть и другие ):

    • гарантирует, что все методы, необходимые для лечения вашего объекта «как ____», есть
    • он самодокументирован, поскольку кто-то, читающий ваш код, может мгновенно узнать, что вы намереваетесь, чтобы ваш объект «действовал как ____».
    • позволяет isinstance(myobject,SomeABC) работать правильно.
    • часто обеспечивает методы автомагическим образом, поэтому мы не должны сами определять их

    (Обратите внимание, что в дополнение к вышесказанному, создание собственной ABC может позволить вам протестировать наличие определенного метода или набора методов в любом объекте и на основе этого объявить, что этот объект является подклассом ABC, даже если объект не наследуется от ABC напрямую . См. этот ответ для получения дополнительной информации. )

    Теперь, в качестве примера, давайте выберем и реализуем ABC для класса в исходном вопросе. Существует два требования:

    1. класс повторяется
    2. доступ к классу по индексу

    Очевидно, что этот класс будет какой-то коллекцией. Итак, что мы будем делать, это посмотреть на наше меню collection ABC, чтобы найти подходящую ABC (обратите внимание, что есть также числовые ABC ). Соответствующая ABC зависит от того, какие абстрактные методы мы хотим использовать в нашем классе.

    Мы видим, что Iterable – это то, что нам нужно, если мы хотим использовать метод __iter__() , который нам нужен, чтобы делать что-то вроде for o in myobject: Однако Iterable не включает метод __getitem__() , который нам нужен, чтобы делать такие вещи, как myobject[i] . Поэтому нам нужно использовать другую ABC.

    В меню collections.abc abstract.abc из абстрактных базовых классов мы видим, что Sequence является самой простой ABC, предлагающей требуемые функции. И – посмотрите ли вы на это – мы получим Iterable функцию как метод mixin, что означает, что нам не нужно определять это самостоятельно – бесплатно! Мы также получаем __contains__ , __reversed__ , index и count . Что, если вы думаете об этом, – это все, что должно быть включено в любой индексированный объект. Если вы забыли включить их, пользователи вашего кода (в том числе, возможно, сами!) Могут получить довольно раздражение (я знаю, что я бы).

    Тем не менее, существует вторая ABC, которая также предлагает эту комбинацию функциональности (итерируемую и доступную по [] ): Mapping . Какой из них мы хотим использовать?

    Напомним, что требование состоит в том, чтобы иметь доступ к объекту по индексу (например, list или tuple ), т. Е. Не по ключу (например, dict ). Поэтому мы выбираем Sequence вместо Mapping .

    Важно отметить, что Sequence myobject[i] = value только для чтения (как и для Mapping ), поэтому он не позволит нам делать такие вещи, как myobject[i] = value или random.shuffle(myobject) . Если мы хотим сделать что-то подобное, нам нужно продолжить движение по меню ABC и использовать MutableSequence (или MutableMapping ).

    Теперь мы можем сделать наш класс. Мы определяем его и наследуем от Sequence .

     from collections.abc import Sequence class MyClass(Sequence): pass 

    Если мы попытаемся использовать его, интерпретатор скажет нам, какие методы нам нужно реализовать до его использования (обратите внимание, что методы также перечислены на странице документов Python):

     >>> myobject = MyClass() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Can't instantiate abstract class MyClass with abstract methods __getitem__, __len__ 

    Это говорит нам о том, что если мы идем дальше и реализуем __getitem__ и __len__ , мы сможем использовать наш новый класс. Мы могли бы сделать это так на Python 3:

     from collections.abc import Sequence class MyClass(Sequence): def __init__(self,L): self.L = L super().__init__() def __getitem__(self, i): return self.L[i] def __len__(self): return len(self.L) # Let's test it: myobject = MyClass([1,2,3]) try: for o in myobject: print(o) print(myobject[0]) except Exception: print("Gah! No good!") raise # No Errors! 

    Оно работает!

    Python - лучший язык программирования в мире.