2014-02-17 4 views
0

Я занимаюсь этим маленьким упражнением ... Я хочу изменить порядок строк на основе какого-то странного словаря. Например, согласно моему словарю, письма приходят в порядке: «а», «б», «г», «C», «F», «е»Наследование от "str" ​​class

Так я понял, что я должен просто перегрузить оператор < для строк и вызова отсортирован()

Здесь идет:

class MyString(str): 
    new_dict = dict((x,i) for i,x in enumerate(["a", "b", "d", "c", "f", "e"])) 
    def __lt__(self,other): 
     return self.new_dict[self] < self.new_dict[other] 
    def __init__(self,x): 
     str.__init__(self,x) 

а потом

In [59]: sorted((MyString(x) for x in "abcdef")) 
Out[59]: ['a', 'b', 'd', 'c', 'f', 'e'] 

Это потрясающе. Или даже:

In [64]: MyString("".join(sorted((MyString(x) for x in "abcdef")))) 
Out[64]: 'abdcfe' 

Но почему я не могу просто сделать sorted(MyString("abcdef"))?

In [70]: sorted(MyString("abcdef")) 
Out[70]: ['a', 'b', 'c', 'd', 'e', 'f'] 

По-видимому, итератор MyString возвращает строки.

In [72]: for i in MyString("abcdef"): 
      print type(i) 
     ....:  
     <type 'str'> 
     <type 'str'> 
     <type 'str'> 
     <type 'str'> 
     <type 'str'> 
     <type 'str'> 

Что произойдет, если я позвоню присоединиться на MyString:

In [63]: type(MyString("").join(sorted((MyString(x) for x in "abcdef")))) 
Out[63]: str 

Почему MyString есть ул итераторы?

+0

'отсортирован()' принимает ключ вместо этого вы можете определить значение сортировки для отсортированных элементов. –

+0

В противном случае сортировка использует '>', '> =', '<=' и '==' также, вам необходимо предоставить * all * операторов. –

ответ

2

Вы должны переопределить __getitem__ method здесь:

class MyString(str): 
    def __getitem__(self, i): 
     return type(self)(super(MyString, self).__getitem__(i)) 

Это возвращает новый экземпляр текущего типа:

>>> for i in MyString("abcdef"): 
...  print type(i) 
... 
<class '__main__.MyString'> 
<class '__main__.MyString'> 
<class '__main__.MyString'> 
<class '__main__.MyString'> 
<class '__main__.MyString'> 
<class '__main__.MyString'> 

str сам по себе не реализует итерации (это не имеет никакого __iter__ menthod, но делает реализации протокола последовательности (то есть как метод __len__ длины аналого __getitem__ метод); именно в этом используется цикл for).

При использовании Python 3, str объекта делает есть метод __iter__ и вам необходимо изменить, что вместо:

class MyString(str): 
    def __iter__(self): 
     return (type(self)(i) for i in super().__iter__()) 

Обратите внимание, что str непреложный тип, перекрывая __init__ оказывает незначительное влияние на экземпляре ,

Для заказа вам действительно нужно реализовать все __gt__, __ge__, __eq__ и т. Д. Методы тоже. Используйте @functools.total_ordering() decorator, чтобы сохранить себя большую часть работы здесь:

from functools import total_ordering 

@total_ordering 
class MyString(str): 
    sortmap = {x: i for i, x in enumerate("abdcfe")} 

    def __lt__(self, other): 
     return self.sortmap[self] < self.sortmap[other] 

    # inherit __eq__ from str 

    def __getitem__(self, i): 
     return type(self)(super(MyString, self).__getitem__(i)) 

И последнее, но не в последнюю очередь, для сортировки, просто использовать key аргумент sorted() здесь:

>>> sortmap = {x: i for i, x in enumerate("abdcfe")} 
>>> sorted('abcdef', key=sortmap.get) 
['a', 'b', 'd', 'c', 'f', 'e'] 
+0

Это бесконечная рекурсия, 'for i in self' вызовет ваш собственный метод' __iter__'. – filmor

+0

@filmor: Упс, я сначала сосредоточился на чем-то другом. Исправленный. –

+0

Я просто играл с этим, пытаясь узнать новые вещи. Ваш ответ потрясающий. Спасибо! – Diana

0

Вам не нужно подкласс для настройки поведения сортировки - вы можете передать параметр key для sort метода или sorted вызова, указав функцию , что дает относительный вес каждого элемента сравниваемых.

Как в:

Защиту MYCOMP (текст): myseq = ("abdcfe") взвешенных = [myseq.find (символ) для полукокса в тексте] возврата взвешенной # это будет разместить -1 для символы, не найденные в вашей картографической строке

0

Вы должны использовать параметр key вместо своего подхода. Причина, по которой не работает, однако, просто, что вы не перегружать __iter__ функции:

class MyString(str): 
    # ... 
    def __iter__(self): 
     for x in super().__iter__(): 
      yield self.__class__(x) 

В Python 2 вы можете использовать

class MyString(str): 
    # ... 
    def __iter__(self): 
     for x in super(MyString, self).__str__(): 
      yield self.__class__(x) 
+0

Это работает только в Python 3; Python 2 'str .__ iter__' не существует. –

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