Substitua __str__ método em objeto de lista em Python
-
06-09-2019 - |
Pergunta
Isto parece que deve ser simples:
Eu quero um list
como qualquer outro list
, exceto que ele tem um método .__str__
diferente.
- tentar definir resultados
object.__str__ = foo
em um erro de somente leitura - Tentando meios
list
subclasse você precisa de alguma maneira de converter umlist
existente para uma instância da subclasse. Isso requer tanto copiar todos os atributos manualmente (uma dor enorme), ou de alguma forma copiá-los todos automaticamente, o que eu não sei como fazer. - Tentando escrever um invólucro em torno dos meios de objetos
list
eu tenho que descobrir uma maneira de enviar todas as mensagens para o objeto embrulhado exceto.__str__
que eu lidar com o meu próprio método. Não sei como fazer isso.
Qualquer alternativas ou soluções # 2 ou # 3 muito apreciada. Obrigado!
Solução
Esta solução funciona sem um wrapper. E funciona se você juntar duas listas por add. Qualquer operação que modifique a lista em si vai funcionar como esperado. Somente funções que retornam uma cópia da lista como: classificado, reveresed retornará a lista python nativa que é bom. tipo e reverter, por outro lado operam sobre a própria lista e manterá o tipo.
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])
Outras dicas
Se você gostaria de substituir __str__
para outros recipientes (por exemplo, tuple
), você pode tirar vantagem de herança múltipla:
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))
Você poderia estender a classe lista e substituí-lo:
class myList(list):
def __str__(self):
# do something
return "something"
Edit: removida uma parte incorreta da resposta que sugeriu dinamicamente substituindo __str__
na lista de objeto, o que não é permitido na implementação de listas Python
Eu sou um programador Java, mas eu acho que é o que você quer (testado com o 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
class MyList(list):
def __str__(self):
return "foo"
str(MyList([1, 2, 3]))
'foo'
str(MyList(list([1, 2, 3])))
'foo'
Os meus comentários anteriores como uma resposta. Como você pode ver MyList aceita qualquer sequência em seu construtor.
O que levanta a questão: por que você quer substituir o método __str__
?Não seria melhor criar uma classe para encapsular o seu objeto?
class MyContainer(object):
def __init__(self, list):
self.containedList = list
def __str__(self):
print('All hail Python')
Desta forma, você não precisa se preocupar com a conversão de seu objeto, ou copiar os atributos, ou qualquer. (A propósito, o quão caro é MyList (longlist)? É uma cópia inteligente, ou um burro "vamos recriar um objeto de lista de um iterável?")
Se, em algum momento, isso parece complicado para fazer o que você está tentando fazer, isso pode significar que você está fazendo errado: p
Como cerca de embrulho lista?
>>> 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']
>>>
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**