2009-05-31 1 views
11

Это кажется, что это должно быть просто:Заменить __str__ метод на объект списка в Python

Я хочу list, как и любой другой list, за исключением того, что имеет другой .__str__ метод.

  1. Попытка установить object.__str__ = foo результатов в ошибке только для чтения
  2. Пытаюсь подкласс list означает, что необходимо каким-то образом преобразовать существующий list к экземпляру подкласса. Для этого требуется либо копирование всех атрибутов вручную (огромная боль), либо как-то копирование их автоматически, что я не знаю, как это сделать.
  3. Попытка написать обертку вокруг объекта list означает, что мне нужно выяснить способ отправки всех сообщений обернутому объекту, кроме .__str__, который я обрабатываю своим методом. Не знаю, как это сделать.

Любые альтернативы или решения # 2 или # 3 очень ценятся. Благодаря!

+2

Адресация 2. Преобразование существующего списка выполняется автоматически, поскольку списки являются итерабельными, а конструктор списка принимает итерабельность. Просто попробуйте myList (anyList). –

+0

Есть ли причина, по которой вы не можете использовать myList для начала? В качестве альтернативы рассмотрите возможность записи функции, которая обертывается вокруг списка, поэтому вы вызываете say pretty_print_list (the_list) вместо str (the_list) – saffsd

+0

@saffsd: это сработает, но вам придется помнить всегда pretty_print вместо печати, что Я пытаюсь избежать. – elliot42

ответ

8

Это решение работает без обертки. И работает, если вы присоедините два списка, добавив. Любая операция, которая модифицирует сам список, будет работать должным образом. Только функции, возвращающие копию списка, например: sorted, reveresed, возвращают собственный список python, который является прекрасным. сортировка и реверс, с другой стороны, работают в самом списке и сохраняют тип.

class myList(list): 
    def __new__(cls, data=None): 
     obj = super(myList, cls).__new__(cls, data) 
     return obj 

    def __str__(self): 
     return 'myList(%s)' % list(self) 

    def __add__(self, other): 
     return myList(list(self) + list(other)) 

>>> l = myList(range(5)) 
>>> print l 
myList([0, 1, 2, 3, 4]) 
>>> print l + [1, 2] 
myList([0, 1, 2, 3, 4, 1, 2]) 
>>> l.sort() 
>>> print l 
myList([0, 1, 2, 3, 4]) 
+0

Это увлекательно и удивительно. Я считаю, что для полного решения необходимо переопределить все методы оператора. Интересно, что потребуется, чтобы отсортировать и отменить работу тоже (не то, что вам нужно ответить, хотя). Благодаря! – elliot42

+2

Возможно, вы захотите заменить первый 'list (self)' супер (myList, self) .__ str __() и 'list (self) + list (other)' by super (myList, self) .__ add __ (other) – NicDumZ

4

Вы можете расширить класс списка и заменить его:

class myList(list): 
    def __str__(self): 
    # do something 
    return "something" 

Edit: убрана неправильную часть ответа, который предложил динамически заменяющего __str__ на объект списка, который не допускается в реализации списков Python ,

+0

Вы не можете изменить список __str__: >>> list ([1, 2, 3]) .__ str__ = myString Traceback (последний последний звонок): Файл «», строка 1, в AttributeError: объект «list» Атрибут '__str__' доступен только для чтения. Но это может быть сделано с наследованием. –

+0

Это кажется близким, но как вы преобразовываете 'list' в' myList'? . Я получил список из списка. Что мне делать с этим? – elliot42

+0

Смотрите мой пост выше. –

2

Я программист Java, но я думаю, что это то, что вы хотите (проверено с Python 2.6):

>>> class myList(list): 
... def __str__(self): 
...  return "aaa" 
... 
>>> def myListWrapper(list): 
... return myList(list) 
... 
>>> a = [1, 2, 3] 
>>> type(a) 
<type 'list'> 
>>> b = myListWrapper(a) 
>>> type(b) 
<class '__main__.myList'> 
>>> print(a) 
[1, 2, 3] 
>>> print(b) 
aaa 
+0

Очень приятно, спасибо. Я не понял, что myList (list) автоматически скопирует все данные из экземпляра списка в экземпляр myList. Я предполагаю, что это происходит только потому, что разработчики списка явно создали функцию типа «копиратор», а не потому, что это является общим для всего наследования. – elliot42

+0

Дальнейшие вопросы были бы, конечно, в том, сколько работы написано этой функцией, которая выполняет все операции копирования. Им приходилось копировать каждый атрибут вручную? – elliot42

+3

класс списка имеет этот конструктор «список (последовательность) -> новый список, инициализированный из элементов последовательности» – dfa

0

Как насчет упаковки список?

>>> class StrList(object): 
    def __init__(self, data=None): 
     self._data = data or [] 
    def __str__(self): 
     return "StrList!" 
    def __getattr__(self, attr): 
     if attr == "_data": 
      return self.__dict__[attr] 
     return getattr(self._data, attr) 
    def __setattr__(self, key, val): 
     if key == "_data": 
      self.__dict__[key] = val 
     else: 
      setattr(self._data, key, val) 
    def __getitem__(self, index): 
     return self._data[index] 
    def __setitem__(self, index, value): 
     self._data[index] = value 


>>> l = StrList(range(3)) 
>>> print l 
StrList! 
>>> l[0] 
0 
>>> for x in l: 
    print x 


0 
1 
2 
>>> l[0] = "spam" 
>>> l.append("egg") 
>>> print list(l) 
['spam', 1, 2, 'egg'] 
>>> 
+0

Это интересно, но, честно говоря, я не понимаю, почему и как l.append в примере работает. Что подсказывает, как передать вызов для добавления из StrList в список внутри него? – elliot42

+1

__getattr__ вызывается, когда вы вызываете объект с помощью метода/члена, которого у него нет. Затем мы можем передать этот вызов до нашего завернутого списка. То же самое относится к __setattr__ et al. Однако, чтобы избежать бесконечной рекурсии, вы должны переопределить вызов на «_data». –

1

Что вызывает вопрос: почему вы хотите переопределить метод __str__?

Не было бы лучше создать класс для инкапсуляции вашего объекта?

class MyContainer(object): 
    def __init__(self, list): 
     self.containedList = list 

    def __str__(self): 
     print('All hail Python') 

Таким образом, вам не придется беспокоиться о преобразовании объекта или копирования атрибутов, или вообще. (кстати, насколько дорогой MyList (longlist)? Это интеллектуальная копия или немой «давайте воссоздать объект списка из итерабельного?»)

Если в какой-то момент вам будет сложно делать то, что вы пытаетесь это сделать, это может означать, что вы делаете это неправильно: p

+0

Если вы инкапсулируете, а не подклассом, вы не получаете все функции списка бесплатно, если вы не переписываете все методы списка в MyContainer, или b) вы всегда должны вызывать * в * container_instance.containedList. Это было бы превосходным решением, если бы у меня был сложный объект, которому также понадобился список внутри него (например, классу нужен список, строка, несколько ints и т. Д.). Но поскольку это все, что мне нужно, список слегка слегка изменен. – elliot42

4

Если вы хотите переопределить __str__ для других контейнеров (например,, tuple), вы можете воспользоваться множественного наследования:

class PrettyStr(object): 
    def __str__(self): 
     ret = '' 

     if isinstance(self, (list, tuple)): 
      ret = ''.join(str(elem) for elem in self) 
     else: 
      pass # handle other types here 

     return ret 


class MyList(PrettyStr, list): 
    pass 


class MyTuple(PrettyStr, tuple): 
    pass 


if __name__ == "__main__": 
    print MyList([1, 2, 3, 4]) 
    print MyTuple((1, 2, 3, 4)) 
+0

Эй, это очень интересно! Благодаря! – elliot42

2
class MyList(list): 
    def __str__(self): 
      return "foo" 

str(MyList([1, 2, 3])) 

'Foo'

str(MyList(list([1, 2, 3]))) 

'Foo'

Мои предыдущие комментарии в ответ. Как вы можете видеть, MyList принимает любую последовательность в своем конструкторе.

-1
Ex = ["a", 2, 4] #our_list 
Ex(-1) = "xuxu_beleza" #the_name_of_your_list(index) = new_item 
Print(Ex) 
["a", 2, "xuxu_beleza"] #our_new_list 

**list[index] = new_item** 
+0

Я не понимаю, как это отвечает на заданный вопрос? – Carpetsmoker

Смежные вопросы