比较字符串时更改 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