[英]Inheriting from “str” class
I'm doing this little exercise... I want to reorder a string based on some weird dictionary. 我正在做这个小练习...我想根据一些奇怪的字典重新排序一个字符串。 For example, according to my dictionary, the letters come in the order: "a", "b", "d", "c", "f", "e"
例如,根据我的字典,字母按顺序排列:“a”,“b”,“d”,“c”,“f”,“e”
So I figured I should just overload the < operator for strings and call sorted() 所以我想我应该重载字符串的<运算符并调用sorted()
Here goes: 开始:
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)
And then 接着
In [59]: sorted((MyString(x) for x in "abcdef"))
Out[59]: ['a', 'b', 'd', 'c', 'f', 'e']
That's awesome. 棒极了。 Or even:
甚至:
In [64]: MyString("".join(sorted((MyString(x) for x in "abcdef"))))
Out[64]: 'abdcfe'
But why can't I just do sorted(MyString("abcdef"))
? 但为什么我不能做
sorted(MyString("abcdef"))
?
In [70]: sorted(MyString("abcdef"))
Out[70]: ['a', 'b', 'c', 'd', 'e', 'f']
Apparently the iterator of MyString is returning strings. 显然,MyString的迭代器正在返回字符串。
In [72]: for i in MyString("abcdef"):
print type(i)
....:
<type 'str'>
<type 'str'>
<type 'str'>
<type 'str'>
<type 'str'>
<type 'str'>
What happens if I call join on MyString: 如果我在MyString上调用join,会发生什么:
In [63]: type(MyString("").join(sorted((MyString(x) for x in "abcdef"))))
Out[63]: str
Why does MyString have str iterators? 为什么MyString有str迭代器?
You need to override the __getitem__
method here: 您需要在此处覆盖
__getitem__
方法 :
class MyString(str):
def __getitem__(self, i):
return type(self)(super(MyString, self).__getitem__(i))
This returns a new instance of the current type: 这将返回当前类型的新实例:
>>> 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
itself doesn't implement iteration (it has no __iter__
menthod , but does implement the sequence protocol (it has both a __len__
length method an a __getitem__
method); it is this that the for
loop ultimately uses). str
本身不实现迭代(它没有__iter__
menthod ,但确实实现了序列协议(它有__len__
长度方法和__getitem__
方法);这是for
循环最终使用的)。
If using Python 3, the str
object does have a __iter__
method and you need to override that instead: 如果使用Python 3,
str
对象确实有一个__iter__
方法,你需要覆盖它:
class MyString(str):
def __iter__(self):
return (type(self)(i) for i in super().__iter__())
Note that str
is an immutable type, overriding __init__
has little influence on the instance. 请注意,
str
是一个不可变类型,覆盖__init__
对实例几乎没有影响。
For ordering, you really need to implement all of the __gt__
, __ge__
, __eq__
, etc. methods too. 如需订购,你真的需要实现所有的
__gt__
, __ge__
, __eq__
等方法了。 Use the @functools.total_ordering()
decorator to save yourself most of the work here: 使用
@functools.total_ordering()
装饰器来保存自己的大部分工作:
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))
Last but not least, for sorting, just use the key
argument to sorted()
here: 最后但并非最不重要的是,对于排序,只需在此处使用
key
参数来sorted()
:
>>> sortmap = {x: i for i, x in enumerate("abdcfe")}
>>> sorted('abcdef', key=sortmap.get)
['a', 'b', 'd', 'c', 'f', 'e']
You don need a subclass for customizing sort behavior - you can pass a key
parameter to a sort
method or sorted
call, specifying a function that gives the relative weights of each element being compared. 您不需要用于自定义排序行为的子类 - 您可以将
key
参数传递给sort
方法或sorted
调用,指定一个函数,该函数提供要比较的每个元素的相对权重。
Like in: 像:
def mycomp(text): myseq = ("abdcfe") weigthed = [myseq.find(char) for char in text] return weigthed # this will place -1's for chars not found in your mapping string def mycomp(text):myseq =(“abdcfe”)weigthed = [myseq.find(char)for char in text] return weigthed#这将为你的映射字符串中找不到的字符放置-1'
You should indeed use the key
parameter instead of your approach. 您确实应该使用
key
参数而不是您的方法。 The reason it is not working however is simply that you didn't overload the __iter__
function: 它不工作的原因只是你没有重载
__iter__
函数:
class MyString(str):
# ...
def __iter__(self):
for x in super().__iter__():
yield self.__class__(x)
In Python 2 you can use 在Python 2中,您可以使用
class MyString(str):
# ...
def __iter__(self):
for x in super(MyString, self).__str__():
yield self.__class__(x)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.