Реализация пользовательского итерируемого объекта в 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
вместо.