为什么 Python 无法理解单词形式的整数?
Why can't Python understand integers in word form?
我无法在任何地方找到我的问题的答案,我对 Python 还是个新手。这个问题的目的主要是了解 Python 是如何工作的以及它有什么限制。
This answer 提供了一个模块,可以将数字从整数转换为整数的单词形式。但是,如果我想 运行 这样的代码,没有任何模块以与 link、
中的模块相反的方式工作
a = "five"
b = 2
if b < a:
print("a is higher than b")
我收到了TypeError: unorderable types: int() < str()
。
那么,为什么 Python 不能将此字符串识别为单词形式的数字?是否符合 "Python has not been built to recognize word forms of numbers"?
注意:我使用 >>>
来演示实际的 python 代码,使用 ?->
来演示假设的 shell
对于如何隐式解析它,有几种可能的情况:
3 < "two"
Python 2 为所有对象定义了一个顺序,这样一列完全任意的对象仍然可以排序,所以所有 str
的计算结果为 more:
>>> 3 < "two" #this is the actual result in python 2
True
另一种方法是将数字转换为等效的字符串,然后按字母顺序比较它们:
>>> "three" < "two"
True
第三种方法是尝试将字符串解析为数字,但由于有太多不同的符号和语言可以用它来写数字几乎不可能每次都得到它 (see this question )
假设我们将其实现为 python 英语
?-> 1 < "two"
True
?-> 1 < "cent" #100 in french
(Traceback)
...
这不是很好,因为有许多程序员可能不会说英语,并且将数字词的解析器实现为每种可能的语言的语言是完全不可能的,如果 1000 > "cent"
评估为 true 时尤其令人困惑您正在使用英文单词 "cent".
现在假设我们已经实现了上面提到的英语解析器,而开发人员决定歧视除英语以外的所有语言,字符串如何相互比较?
如果 python 中比较字符串的行为没有改变,它将在比较中造成巨大的不一致:
>>> "five" < "three"
True
?-> "three" == 3
True
?-> "five" > 3 == "three"
True
?-> "five" < "three" == 3
True
?-> "ONE" == "one"
False
?-> "one" == 1 == "ONE"
True
或者假设您尝试将两个字符串都转换为数字并将它们作为数字进行比较,那么排序字符串就会中断:
?-> words = "please give me five apples".split()
?-> words.sort()
?-> words
['five', 'apples', 'give', 'me', 'please']
所以基本上无论你怎么看,隐含地添加这个功能都会完全破坏许多其他非常好的功能。
编辑
我很好奇排序实际上是如何工作的,所以我创建了一个 class 来实际进行这种比较:
from functools import total_ordering
@total_ordering
class number_word:
key = dict(enumerate(
("zero one two three four five six seven eight nine ten".split())
))
key.update({v:k for k,v in key.items()})
def __init__(self,value):
alt = self.key.get(value,None)
if isinstance(value,str):
self.word = value
self.num = alt
elif isinstance(value,int):
self.num = value
self.word = alt
else:
raise TypeError("must be str or int")
def __repr__(self):
return "nw(%r)"%self.word
def __eq__(self,other):
if not isinstance(other,number_word):
other = word_number(other)
if self.num == None == other.num:
#neither are valid numbers, compare as strings
return self.word == other.word
else:
return self.num == other.num
def __lt__(self,other):
if not isinstance(other,number_word):
other = word_number(other)
if self.num is None or other.num is None:
return self.word < other.word
else:
return self.num < other.num
这样number_word(2) < number_word("five")
就会被判断为真,看一下字符串的排序:
words = "range(1,6) goes from one to five".split()
correct = sorted(words)
num_sort = sorted(words,key=number_word)
backward = sorted(words,key=number_word, reverse=True)
print(correct)
print(num_sort)
print(backward[::-1])
理论上这三个应该是相同的,尤其是 num_sort == backward[::-1]
但这是结果:
['five', 'from', 'goes', 'one', 'range(1,6)', 'to']
['from', 'goes', 'one', 'five', 'range(1,6)', 'to']
['one', 'five', 'from', 'goes', 'range(1,6)', 'to']
所以是的,它确实破坏了字符串排序。
我无法在任何地方找到我的问题的答案,我对 Python 还是个新手。这个问题的目的主要是了解 Python 是如何工作的以及它有什么限制。 This answer 提供了一个模块,可以将数字从整数转换为整数的单词形式。但是,如果我想 运行 这样的代码,没有任何模块以与 link、
中的模块相反的方式工作a = "five"
b = 2
if b < a:
print("a is higher than b")
我收到了TypeError: unorderable types: int() < str()
。
那么,为什么 Python 不能将此字符串识别为单词形式的数字?是否符合 "Python has not been built to recognize word forms of numbers"?
注意:我使用 >>>
来演示实际的 python 代码,使用 ?->
来演示假设的 shell
对于如何隐式解析它,有几种可能的情况:
3 < "two"
Python 2 为所有对象定义了一个顺序,这样一列完全任意的对象仍然可以排序,所以所有 str
的计算结果为 more:
>>> 3 < "two" #this is the actual result in python 2
True
另一种方法是将数字转换为等效的字符串,然后按字母顺序比较它们:
>>> "three" < "two"
True
第三种方法是尝试将字符串解析为数字,但由于有太多不同的符号和语言可以用它来写数字几乎不可能每次都得到它 (see this question )
假设我们将其实现为 python 英语
?-> 1 < "two"
True
?-> 1 < "cent" #100 in french
(Traceback)
...
这不是很好,因为有许多程序员可能不会说英语,并且将数字词的解析器实现为每种可能的语言的语言是完全不可能的,如果 1000 > "cent"
评估为 true 时尤其令人困惑您正在使用英文单词 "cent".
现在假设我们已经实现了上面提到的英语解析器,而开发人员决定歧视除英语以外的所有语言,字符串如何相互比较?
如果 python 中比较字符串的行为没有改变,它将在比较中造成巨大的不一致:
>>> "five" < "three"
True
?-> "three" == 3
True
?-> "five" > 3 == "three"
True
?-> "five" < "three" == 3
True
?-> "ONE" == "one"
False
?-> "one" == 1 == "ONE"
True
或者假设您尝试将两个字符串都转换为数字并将它们作为数字进行比较,那么排序字符串就会中断:
?-> words = "please give me five apples".split()
?-> words.sort()
?-> words
['five', 'apples', 'give', 'me', 'please']
所以基本上无论你怎么看,隐含地添加这个功能都会完全破坏许多其他非常好的功能。
编辑
我很好奇排序实际上是如何工作的,所以我创建了一个 class 来实际进行这种比较:
from functools import total_ordering
@total_ordering
class number_word:
key = dict(enumerate(
("zero one two three four five six seven eight nine ten".split())
))
key.update({v:k for k,v in key.items()})
def __init__(self,value):
alt = self.key.get(value,None)
if isinstance(value,str):
self.word = value
self.num = alt
elif isinstance(value,int):
self.num = value
self.word = alt
else:
raise TypeError("must be str or int")
def __repr__(self):
return "nw(%r)"%self.word
def __eq__(self,other):
if not isinstance(other,number_word):
other = word_number(other)
if self.num == None == other.num:
#neither are valid numbers, compare as strings
return self.word == other.word
else:
return self.num == other.num
def __lt__(self,other):
if not isinstance(other,number_word):
other = word_number(other)
if self.num is None or other.num is None:
return self.word < other.word
else:
return self.num < other.num
这样number_word(2) < number_word("five")
就会被判断为真,看一下字符串的排序:
words = "range(1,6) goes from one to five".split()
correct = sorted(words)
num_sort = sorted(words,key=number_word)
backward = sorted(words,key=number_word, reverse=True)
print(correct)
print(num_sort)
print(backward[::-1])
理论上这三个应该是相同的,尤其是 num_sort == backward[::-1]
但这是结果:
['five', 'from', 'goes', 'one', 'range(1,6)', 'to']
['from', 'goes', 'one', 'five', 'range(1,6)', 'to']
['one', 'five', 'from', 'goes', 'range(1,6)', 'to']
所以是的,它确实破坏了字符串排序。