Реализация пользовательского итерируемого объекта в Python

Это моя реализация настраиваемого односвязного списка в Python.

 class SList:
        def __init__(self):
            self.root = None
            self.size = 0

        def insert(self, item):
            if not item:
                raise ValueError('Cannot add None item to a list')
            self.size += 1
            if self.root is None:
                self.root = Node(item)
            else:
                p = Node(item)
                p.next = self.root
                self.root = p

        """Remove the element at the specific index"""
        def remove(self, index):
            if index < 0 or index >= self.size:
                raise ValueError('Index cannot be negative or greater than the size of the list')

            current = self.root
            if index == 0:
                self.root = self.root.next
            else:
                for _ in range(index -1):
                    current = current.next
                p = current.next.next
                if p is not None:
                    current.next = p
                else:
                    current.next = None

            self.size -= 1

        def __len__(self):
            return self.size

        def __repr__(self):
            res = '[ '
            current = self.root
            while current is not None:
                res += str(current.data)
                res += ' '
                current = current.next
            res += ']'
            return res

        def __iter__(self):
            return self

        def next(self):
            ........

Это объект Node

class Node:
    def __init__(self, data):
        try:
            if not data:
                raise ValueError
            self.data = data
            self.next = None
        except ValueError:
            raise ValueError('Node cannot be instantiated without an item')

Я немного растерялся при реализации этого метода. Я вижу, что есть несколько способов реализовать это, и выход, кажется, является общим путем продвижения вперед. Был бы признателен за помощь в реализации с yield

2 ответа

Решение

Вы можете сделать свой класс повторяемым, сделав его __iter__ метод генератор.

Вот код, который правильно работает на Python 2 или Python 3.

from __future__ import print_function

class Node(object):
    def __init__(self, data):
        if data is None:
            raise ValueError('Node cannot be instantiated without an item')
        self.data = data
        self.nextnode = None

    def __repr__(self):
        return 'Node({})'.format(self.data)

class SList(object):
    def __init__(self):
        self.root = None
        self.size = 0

    def insert(self, item):
        if item is None:
            raise ValueError('Cannot add None item to a list')
        self.size += 1
        if self.root is None:
            self.root = Node(item)
        else:
            p = Node(item)
            p.nextnode = self.root
            self.root = p

    def remove(self, index):
        """ Remove the element at the specific index """
        if index < 0 or index >= self.size:
            raise ValueError('Index cannot be negative or greater than the size of the list')

        current = self.root
        if index == 0:
            self.root = self.root.nextnode
        else:
            for _ in range(index - 1):
                current = current.nextnode
            current.nextnode = current.nextnode.nextnode

        self.size -= 1

    def __len__(self):
        return self.size

    def __repr__(self):
        res = []
        current = self.root
        while current is not None:
            res.append(current.data)
            current = current.nextnode
        return str(res)

    def __iter__(self):
        current = self.root
        while current is not None:
            yield current
            current = current.nextnode

# test 

a = SList()
for c in 'ABCDE':
    a.insert(c)

print(a)

gen = iter(a)
print('root', next(gen))
for node in gen:
    print(node)

a.remove(2)

print(list(a))

for node in a:
    print(node)

выход

['E', 'D', 'C', 'B', 'A']
root Node(E)
Node(D)
Node(C)
Node(B)
Node(A)
[Node(E), Node(D), Node(B), Node(A)]
Node(E)
Node(D)
Node(B)
Node(A)

Попробуйте следовать этому объяснению: pythontips.com/2013/09/29/the-python-yield-keyword-explained

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

def my_gen(arg):
    yield arg * 10
    for i in xrange(5):
            if i / 2 == 0:
                 yield i

for x in my_gen(3):
     print(x) 

Распечатает: 30 0 2 4

Конструктор класса Node также неисправен, кроме того, что вы перехватываете собственное исключение, у вас также есть ошибка с условием if not data будет True не только, если data равно False или None, но также если data равно 0, пустой список, пустая строка и многое другое. использование data is None вместо.

Другие вопросы по тегам