继承自“str”类

时间:2014-02-17 11:50:13

标签: python inheritance operator-overloading

我正在做这个小小的练习...... 我想基于一些奇怪的字典重新排序字符串。 例如,根据我的字典,字母按顺序排列: “a”,“b”,“d”,“c”,“f”,“e”

所以我想我应该重载<字符串的运算符和调用sorted()

这里是:

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上调用join,会发生什么:

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

为什么MyString有str迭代器?

3 个答案:

答案 0 :(得分: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']

答案 1 :(得分:0)

您不需要子类来自定义排序行为 - 您可以将key参数传递给sort方法或sorted调用,指定一个函数 它给出了被比较的每个元素的相对权重。

喜欢在:

def mycomp(文字):     myseq =(“abdcfe”)     weigthed = [myseq.find(char)for char in text]     return weigthed#这将为你的映射字符串中找不到的字符放置-1'

答案 2 :(得分: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)