Is there any way I can make Python "think" that 5 > 6, or that some other arbitrary math/string equation is interpreted in a specific way?
I mainly want to take a string with a symbol and automatically make it larger than the other, so that "⇟" > "◈"
evaluates to True
.
I know you can assign these symbols to numbers, but if there is an easier way to do this, it could be more efficient.
This is a basic idea of what I want:
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")
Since Python already has something like this programmed in, I want to change it so that I can create my own symbols that are either greater than or less than the other symbol, without the interruption of Python's automatic string comparisons.
This is fairly simple if you define your own integer class:
class BadInteger(int):
def __gt__(self, other):
return super().__lt__(other)
print(BadInteger(5) > BadInteger(6)) # prints True
The BadInteger
class is based on the int
class (i.e. the regular Python integer). But in this case, we reversed how a "greater than" comparison works by reimplementing the __gt__
special method ("gt" stands for "greater than"). The implementation simply calls the integer's implementation of __lt__
("less than").
This effectively means that, when we try to compare two BadInteger
s using >
, it will work as if we compared two regular integers with <
. If the "greater than" comparson would evaluate to True
with regular integers, it will now evaluate to False
with our BadInteger
class, and vice-versa.
You still need to reimplement any other relevant methods, so that they work the opposite way (e.g., __ge__
for the "greater than or equal" operator (>=
), __lt__
for "less than" (<
), etc). But this sets the base to achieve what you want.
Since you edited your original question, here's a follow-up answer.
We can once again define a custom class in order to implement the functionality you want. Consider this:
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)
The MySymbol
class takes a symbol and an optional value as the input. You may have seen where this is going, but the symbol represents your string, and the value is a number used in comparisons.
Since we have implementations for the __gt__
, __ge__
and __eq__
magic methods, our symbols "know" how to be compared to one another with the >
, >=
and ==
operators, respectively.
Additionally, Python is smart enough to re-use these implementations and simply flip the result around - so we also get <
, <=
and !=
for free.
Now this might not be exactly what you hoped for, because we still have to inform what is the specific value of each symbol we create. But this is the price to pay when creating a custom comparison - at some point in your program, you're gonna have to declare which of your custom symbols is greater than the rest, and vice-versa. Python won't ever "just know" that you're trying to compare things in an unusual fashion without you ever telling Python that you want to do so.
Quick demo:
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
And following your example:
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")
Example output:
Type in a symbol: !
Type in its value: 100
Type in a second symbol: #
Type in its value: 10
firstSymbol > secondSymbol