Support for __rlt__, __rle__, ...
Support for __rlt__, __rle__, ...
Does micropython support __rlt__, __rle__, __req__, __rne__, __rgt__ and __rge__?
I include them in my class to compare 'int' numbers to class objects but micropython does not seem to call them. An exception of this kind occurs: "TypeError: unsupported types for __lt__"
The same code works with Python.
I include them in my class to compare 'int' numbers to class objects but micropython does not seem to call them. An exception of this kind occurs: "TypeError: unsupported types for __lt__"
The same code works with Python.
Re: Support for __rlt__, __rle__, ...
Yes, but only when MICROPY_PY_REVERSE_SPECIAL_METHODS is enabled at compile time. For some reason it isn't enabled on ESP32, but is on STM32 and Pico.
Re: Support for __rlt__, __rle__, ...
Raised https://github.com/micropython/micropython/pull/7613 to get this added to ESP32
Re: Support for __rlt__, __rle__, ...
That's strange. I am using a Raspberry Pi Pico:
Implementation name: micropython
Implementation version: 1.16.0
Implementation platform: rp2
Re: Support for __rlt__, __rle__, ...
huh... maybe could you share your code? Or a simple snippet that shows the problem?
Re: Support for __rlt__, __rle__, ...
After investigating a bit further, I can see that the problem is related to reverse operators, but not as I thought. This is a small bit of code that shows the problem:
Code: Select all
import sys
if sys.implementation.name == "micropython":
import machine
class TestNumber():
def __init__(self, n: int) -> None:
self.number = n
def __lt__(self, other: "TestNumber") -> bool:
print(self, "__lt__", other)
if isinstance(other, int):
other = TestNumber(other)
return (self.number < other.number)
def __gt__(self, other: "TestNumber") -> bool:
print(self, "__gt__", other)
if isinstance(other, int):
other = TestNumber(other)
return (self.number > other.number)
def __floordiv__(self, other: "TestNumber") -> "TestNumber":
print(self, "__floordiv__", other)
if isinstance(other, int):
other = TestNumber(other)
return TestNumber(self.number // other.number)
def __rfloordiv__(self, other: int) -> "DecimalNumber":
print(self, "__rfloordiv__", other)
return TestNumber(other).__floordiv__(self)
def __str__(self) -> str:
return str(self.number)
print("Implementation name:", sys.implementation.name)
print("Implementation version:", "{0}.{1}.{2}".format(
sys.implementation.version[0],
sys.implementation.version[1],
sys.implementation.version[2]
)
)
print("Implementation platform:", sys.platform)
b = TestNumber(5)
print("-" * 78)
print("b =", b)
print("-" * 78)
try:
if (3).__lt__(b) is NotImplemented:
print("'int' < 'TestNumber' not implemented. Python should try b.__gt__(3)")
print("3 < b: ", (3 < b))
except Exception as e:
print("Exception: ", e)
print("-" * 78)
try:
if (15).__floordiv__(b) is NotImplemented:
print("'int' // 'TestNumber' not implemented. Python should try b.__rfloordiv__(15)")
print("15 // b =", 15 // b)
except Exception as e:
print("Exception: ", e)
Code: Select all
Implementation name: cpython
Implementation version: 3.6.9
Implementation platform: linux
------------------------------------------------------------------------------
b = 5
------------------------------------------------------------------------------
'int' < 'TestNumber' not implemented. Python should try b.__gt__(3)
5 __gt__ 3
3 < b: True
------------------------------------------------------------------------------
'int' // 'TestNumber' not implemented. Python should try b.__rfloordiv__(15)
5 __rfloordiv__ 15
15 __floordiv__ 5
15 // b = 3
Code: Select all
Implementation name: micropython
Implementation version: 1.16.0
Implementation platform: rp2
------------------------------------------------------------------------------
b = 5
------------------------------------------------------------------------------
Exception: 'int' object has no attribute '__lt__'
------------------------------------------------------------------------------
Exception: 'int' object has no attribute '__floordiv__'
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Support for __rlt__, __rle__, ...
I see the same result on the Unix build and on a Pyboard. I'm no expert on the build system but all seem to be defined with MICROPY_PY_REVERSE_SPECIAL_METHODS set.
FWIW my quaternion class uses a lot of these special methods and has run on a Pyboard. However it doesn't use __lt__ or __floordiv__ so maybe these are special cases of missing methods?
Code: Select all
[adminpete@capybara]: /mnt/qnap2/data/Projects/MicroPython/micropython/ports
$ grep --include=\*.h -rnw '.' -e "MICROPY_PY_REVERSE_SPECIAL_METHODS"
./rp2/mpconfigport.h:87:#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
./mimxrt/mpconfigport.h:82:#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
./qemu-arm/mpconfigport.h:29:#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
./stm32/mpconfigport.h:104:#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
./windows/mpconfigport.h:82:#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
./unix/variants/coverage/mpconfigvariant.h:44:#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
./unix/mpconfigport.h:104:#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Support for __rlt__, __rle__, ...
I see my misunderstanding now -- the topic of the post was "Support for __rlt__, __rle__, ..." which is what made me think reverse operators, but looking more closely, there is no such thing as reverse (i.e. __r...__) comparison operators and the behavior you're expecting is a different feature.
Specifically, at https://docs.python.org/3/reference/dat ... bject.__ge__
"There are no swapped-argument versions of these methods (to be used when the left argument does not support the operation but the right argument does); rather, __lt__() and __gt__() are each other’s reflection, __le__() and __ge__() are each other’s reflection, and __eq__() and __ne__() are their own reflection. If the operands are of different types, and right operand’s type is a direct or indirect subclass of the left operand’s type, the reflected method of the right operand has priority, otherwise the left operand’s method has priority. Virtual subclassing is not considered."
MicroPython does not currently implement this behaviour... although it probably should.
The other thing we don't do is support the operators returning NotImplemented... which is why in your sample program you get the error about "Exception: 'int' object has no attribute '__lt__'" which comes from the
Code: Select all
if (3).__lt__(b) is NotImplemented:
Re: Support for __rlt__, __rle__, ...
Thanks a lot for your help, jimmo.jimmo wrote: ↑Thu Aug 05, 2021 5:15 am
. . . . .
MicroPython does not currently implement this behaviour... although it probably should.
The other thing we don't do is support the operators returning NotImplemented... which is why in your sample program you get the error about "Exception: 'int' object has no attribute '__lt__'" which comes from theline, and not the actual use of the < operator.Code: Select all
if (3).__lt__(b) is NotImplemented:
I also think that it is a core feature that should probably be implemented, but I do not know what it will require or the difficulty/possibility of adding it to micropython.
I find it limiting. I have finished the development of a module for micropython in the line of 'decimal', part of the Python Standard Library, to provide floating point arithmetic with arbitrary precision to micropython. Without the functionality we have been discussing, it can work on micropython as long as operations are performed between class objects or, when using 'int' and class objects, 'int' is used on the right hand side of the operator. For example, (a > 5) is possible but (5 < a) is not.
By the way, it will be available on GitHub as soon as I finish the testing and documentation.