По сути, я бы основывал свое собственное решение на рекурсии. Я бы расширил класс контейнера следующим образом:
cursor_position
- Свойство, в котором хранится индекс выделенного элемента (или элемента, который содержит элемент, содержащий выделенный элемент, или любой уровень рекурсии за его пределами).
repr_with_cursor
- Этот метод должен возвращать версию содержимого контейнера для печати, уже выделяя элемент, выбранный в данный момент.
mov_right
- этот метод должен вызываться, когда курсор перемещается вправо. Возвращает новый индекс курсора в элементе или None
, если курсор находится «вне» текущего контейнера (если вы перемещаетесь за последний элемент в контейнере.
mov_left
- То же самое, но влево.
Способ, которым должна работать рекурсия, заключается в том, что для каждого метода, в зависимости от типа выделенного метода, у вас должно быть два различных поведения:
- , если курсор находится на контейнере , он должен вызывать метод "заостренного" контейнера.
- если курсор находится на неконтейнере , он должен выполнять «реальную вещь».
EDIT
У меня было свободное полчаса, поэтому я собрал пример класса, который реализует мою идею. Это не полная функция (например, он не справляется хорошо, когда достигает любого конца самого большого контейнера, и требует, чтобы каждый экземпляр класса использовался только один раз в самой большой последовательности), но он работает достаточно, чтобы продемонстрировать концепцию , Я повторю, прежде чем люди прокомментируют это: это проверочный код, он никоим образом не готов к использованию!
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class C(list):
def __init__(self, *args):
self.cursor_position = None
super(C, self).__init__(*args)
def _pointed(self):
'''Return currently pointed item'''
if self.cursor_position == None:
return None
return self[self.cursor_position]
def _recursable(self):
'''Return True if pointed item is a container [C class]'''
return (type(self._pointed()) == C)
def init_pointer(self, end):
'''
Recursively set the pointers of containers in a way to point to the
first non-container item of the nested hierarchy.
'''
assert end in ('left', 'right')
val = 0 if end == 'left' else len(self)-1
self.cursor_position = val
if self._recursable():
self.pointed._init_pointer(end)
def repr_with_cursor(self):
'''
Return a representation of the container with highlighted item.
'''
composite = '['
for i, elem in enumerate(self):
if type(elem) == C:
composite += elem.repr_with_cursor()
else:
if i != self.cursor_position:
composite += str(elem)
else:
composite += '**' + str(elem) + '**'
if i != len(self)-1:
composite += ', '
composite += ']'
return composite
def mov_right(self):
'''
Move pointer to the right.
'''
if self._recursable():
if self._pointed().mov_right() == -1:
if self.cursor_position != len(self)-1:
self.cursor_position += 1
else:
if self.cursor_position != len(self)-1:
self.cursor_position += 1
if self._recursable():
self._pointed().init_pointer('left')
else:
self.cursor_position = None
return -1
def mov_left(self):
'''
Move pointer to the left.
'''
if self._recursable():
if self._pointed().mov_left() == -1:
if self.cursor_position != 0:
self.cursor_position -= 1
else:
if self.cursor_position != 0:
self.cursor_position -= 1
if self._recursable():
self._pointed().init_pointer('right')
else:
self.cursor_position = None
return -1
Простой тестовый скрипт:
# Create the nested structure
LevelOne = C(('I say',))
LevelTwo = C(('Hello', 'Bye', 'Ciao'))
LevelOne.append(LevelTwo)
LevelOne.append('!')
LevelOne.init_pointer('left')
# The container's content can be seen as both a regualar list or a
# special container.
print(LevelOne)
print(LevelOne.repr_with_cursor())
print('---')
# Showcase the effect of moving the cursor to right
for i in range(5):
print(LevelOne.repr_with_cursor())
LevelOne.mov_right()
print('---')
# Showcase the effect of moving the cursor to left
LevelOne.init_pointer('right')
for i in range(5):
print(LevelOne.repr_with_cursor())
LevelOne.mov_left()
Выводит:
['I say', ['Hello', 'Bye', 'Ciao'], '!']
[**I say**, [Hello, Bye, Ciao], !]
---
[**I say**, [Hello, Bye, Ciao], !]
[I say, [**Hello**, Bye, Ciao], !]
[I say, [Hello, **Bye**, Ciao], !]
[I say, [Hello, Bye, **Ciao**], !]
[I say, [Hello, Bye, Ciao], **!**]
---
[I say, [Hello, Bye, Ciao], **!**]
[I say, [Hello, Bye, **Ciao**], !]
[I say, [Hello, **Bye**, Ciao], !]
[I say, [**Hello**, Bye, Ciao], !]
[**I say**, [Hello, Bye, Ciao], !]
Забавная проблема! Мой любимый вопрос ОС сегодня! :)