比较字符串时更改 Python 的默认逻辑
Change Python's default logic when comparing strings
有什么方法可以让 Python“认为”5 > 6,或者其他任意 math/string 等式以特定方式解释?
我主要是想把一个带符号的字符串自动变大,这样"⇟" > "◈"
就等于True
.
我知道您可以将这些符号分配给数字,但如果有更简单的方法,效率会更高。
这是我想要的基本思路:
firstSymbol = input("Type in a symbol: ")
secondSymbol = input("Type in a second symbol: ")
if firstSymbol > secondSymbol:
print("firstSymbol > secondSymbol")
elif secondSymbol > firstSymbol:
print("secondSymbol > firstSymbol")
elif firstSymbol == secondSymbol:
print("Your two symbols are equal")
因为 Python 已经有了这样的程序,我想改变它,这样我就可以创建自己的符号,这些符号大于或小于其他符号,而不会中断 Python 的自动字符串比较。
如果您定义自己的整数,这就相当简单 class:
class BadInteger(int):
def __gt__(self, other):
return super().__lt__(other)
print(BadInteger(5) > BadInteger(6)) # prints True
BadInteger
class 基于 int
class (即常规 Python 整数)。但在这种情况下,我们通过重新实现 __gt__
特殊方法(“gt”代表“大于”)来反转“大于”比较的工作方式。该实现简单地调用整数的实现 __lt__
(“小于”)。
这实际上意味着,当我们尝试使用 >
比较两个 BadInteger
时,它的工作方式就好像我们使用 <
比较两个常规整数一样。如果“大于”比较器对常规整数的计算结果为 True
,则现在对我们的 BadInteger
class 的计算结果为 False
,反之亦然。
您仍然需要重新实现任何其他相关方法,以便它们以相反的方式工作(例如,__ge__
用于“大于或等于”运算符 (>=
),__lt__
表示“小于”(<
)等)。但这为实现您想要的目标奠定了基础。
编辑
由于您编辑了原始问题,这里有一个后续答案。
我们可以再次定义自定义 class 以实现您想要的功能。考虑一下:
class MySymbol:
def __init__(self, symbol, value = None):
if len(symbol) != 1:
raise ValueError('Symbol string must have length 1')
if value is None:
value = ord(symbol)
self.symbol = symbol
self.value = value
def __str__(self):
return self.symbol
def __repr__(self):
return f'MySymbol(symbol={self.symbol}, value={self.value})'
def __gt__(self, other):
self.check_instance(other=other)
return self.value > other.value
def __ge__(self, other):
self.check_instance(other=other)
return self.value >= other.value
def __eq__(self, other):
self.check_instance(other=other)
return self.value == other.value
def check_instance(self, other):
if not isinstance(other, MySymbol):
error_message = (
f"'==' not supported between instances of"
f" '{self.__class__.__name__}' and"
f" '{other.__class__.__name__}'"
)
raise TypeError(error_message)
MySymbol
class 将一个符号和一个可选值作为输入。您可能已经看到这是怎么回事,但是符号代表您的字符串,而值是用于比较的数字。
由于我们实现了 __gt__
、__ge__
和 __eq__
魔术方法,我们的符号“知道”如何使用 >
相互比较, >=
和 ==
运算符。
此外,Python 足够聪明,可以重用这些实现并简单地翻转结果 - 所以我们也得到 <
、<=
和 !=
免费。
现在这可能不完全您所希望的,因为我们仍然需要告知我们创建的每个符号的具体值是多少。但这是创建自定义比较时要付出的代价 - 在您的程序中的某个时刻,您将不得不声明您的自定义符号中的哪个大于其余符号,反之亦然。 Python 永远不会“只知道”你正试图以一种不寻常的方式比较事物,除非你告诉 Python 你想要这样做。
快速演示:
firstSymbol = MySymbol('w', 30)
secondSymbol = MySymbol('$', 108)
firstSymbol != secondSymbol
# True
firstSymbol > secondSymbol
# False
# Note that it will use Python's default string values if we don't provide one
thirdSymbol = MySymbol('a')
fourthSymbol = MySymbol('b')
thirdSymbol > fourthSymbol # same as comparing 'a' > 'b'
# False
并以您为例:
s1 = input("Type in a symbol: ")
v1_text = input("Type in its value: ")
try:
v1 = int(v1_text)
except ValueError: # use default string value
v1 = None
s2 = input("Type in a second symbol: ")
v2_text = input("Type in its value: ")
try:
v2 = int(v2_text)
except ValueError: # use default string value
v2 = None
firstSymbol = MySymbol(s1, v1)
secondSymbol = MySymbol(s2, v2)
if firstSymbol > secondSymbol:
print("firstSymbol > secondSymbol")
elif secondSymbol > firstSymbol:
print("secondSymbol > firstSymbol")
elif firstSymbol == secondSymbol:
print("Your two symbols are equal")
示例输出:
Type in a symbol: !
Type in its value: 100
Type in a second symbol: #
Type in its value: 10
firstSymbol > secondSymbol
有什么方法可以让 Python“认为”5 > 6,或者其他任意 math/string 等式以特定方式解释?
我主要是想把一个带符号的字符串自动变大,这样"⇟" > "◈"
就等于True
.
我知道您可以将这些符号分配给数字,但如果有更简单的方法,效率会更高。
这是我想要的基本思路:
firstSymbol = input("Type in a symbol: ")
secondSymbol = input("Type in a second symbol: ")
if firstSymbol > secondSymbol:
print("firstSymbol > secondSymbol")
elif secondSymbol > firstSymbol:
print("secondSymbol > firstSymbol")
elif firstSymbol == secondSymbol:
print("Your two symbols are equal")
因为 Python 已经有了这样的程序,我想改变它,这样我就可以创建自己的符号,这些符号大于或小于其他符号,而不会中断 Python 的自动字符串比较。
如果您定义自己的整数,这就相当简单 class:
class BadInteger(int):
def __gt__(self, other):
return super().__lt__(other)
print(BadInteger(5) > BadInteger(6)) # prints True
BadInteger
class 基于 int
class (即常规 Python 整数)。但在这种情况下,我们通过重新实现 __gt__
特殊方法(“gt”代表“大于”)来反转“大于”比较的工作方式。该实现简单地调用整数的实现 __lt__
(“小于”)。
这实际上意味着,当我们尝试使用 >
比较两个 BadInteger
时,它的工作方式就好像我们使用 <
比较两个常规整数一样。如果“大于”比较器对常规整数的计算结果为 True
,则现在对我们的 BadInteger
class 的计算结果为 False
,反之亦然。
您仍然需要重新实现任何其他相关方法,以便它们以相反的方式工作(例如,__ge__
用于“大于或等于”运算符 (>=
),__lt__
表示“小于”(<
)等)。但这为实现您想要的目标奠定了基础。
编辑
由于您编辑了原始问题,这里有一个后续答案。
我们可以再次定义自定义 class 以实现您想要的功能。考虑一下:
class MySymbol:
def __init__(self, symbol, value = None):
if len(symbol) != 1:
raise ValueError('Symbol string must have length 1')
if value is None:
value = ord(symbol)
self.symbol = symbol
self.value = value
def __str__(self):
return self.symbol
def __repr__(self):
return f'MySymbol(symbol={self.symbol}, value={self.value})'
def __gt__(self, other):
self.check_instance(other=other)
return self.value > other.value
def __ge__(self, other):
self.check_instance(other=other)
return self.value >= other.value
def __eq__(self, other):
self.check_instance(other=other)
return self.value == other.value
def check_instance(self, other):
if not isinstance(other, MySymbol):
error_message = (
f"'==' not supported between instances of"
f" '{self.__class__.__name__}' and"
f" '{other.__class__.__name__}'"
)
raise TypeError(error_message)
MySymbol
class 将一个符号和一个可选值作为输入。您可能已经看到这是怎么回事,但是符号代表您的字符串,而值是用于比较的数字。
由于我们实现了 __gt__
、__ge__
和 __eq__
魔术方法,我们的符号“知道”如何使用 >
相互比较, >=
和 ==
运算符。
此外,Python 足够聪明,可以重用这些实现并简单地翻转结果 - 所以我们也得到 <
、<=
和 !=
免费。
现在这可能不完全您所希望的,因为我们仍然需要告知我们创建的每个符号的具体值是多少。但这是创建自定义比较时要付出的代价 - 在您的程序中的某个时刻,您将不得不声明您的自定义符号中的哪个大于其余符号,反之亦然。 Python 永远不会“只知道”你正试图以一种不寻常的方式比较事物,除非你告诉 Python 你想要这样做。
快速演示:
firstSymbol = MySymbol('w', 30)
secondSymbol = MySymbol('$', 108)
firstSymbol != secondSymbol
# True
firstSymbol > secondSymbol
# False
# Note that it will use Python's default string values if we don't provide one
thirdSymbol = MySymbol('a')
fourthSymbol = MySymbol('b')
thirdSymbol > fourthSymbol # same as comparing 'a' > 'b'
# False
并以您为例:
s1 = input("Type in a symbol: ")
v1_text = input("Type in its value: ")
try:
v1 = int(v1_text)
except ValueError: # use default string value
v1 = None
s2 = input("Type in a second symbol: ")
v2_text = input("Type in its value: ")
try:
v2 = int(v2_text)
except ValueError: # use default string value
v2 = None
firstSymbol = MySymbol(s1, v1)
secondSymbol = MySymbol(s2, v2)
if firstSymbol > secondSymbol:
print("firstSymbol > secondSymbol")
elif secondSymbol > firstSymbol:
print("secondSymbol > firstSymbol")
elif firstSymbol == secondSymbol:
print("Your two symbols are equal")
示例输出:
Type in a symbol: !
Type in its value: 100
Type in a second symbol: #
Type in its value: 10
firstSymbol > secondSymbol