I wish to add local functionality to the LED class, but have run into something that baffles me. Here is code reproduced from REPL with a v1.1 pyBoard, v1.11 code.
----------------------------------------------
>>> from pyb import LED
>>> class MyLed(LED):
... def __init__(self):
... self.led1_obj = LED(1)
... self.led2_obj = LED(2)
... self.led1_obj.toggle()
... self.led2_obj.toggle()
...
>>> leds = MyLed()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function takes 1 positional arguments but 0 were given
---------------------------------------------
The leds do indeed toggle when I try to create the <leds> object (the last line). Why won't it create the object? Thanks.
Subclass of LED
Re: Subclass of LED
The simple not-very-helpful answer here is that inheriting from built-in classes can lead to some surprises in MicroPython and generally it's a bad idea. The error you're seeing is that the built-in LED.__init__ is being called with no arguments.
I'll come back to a better explanation, but I'm not sure that deriving from LED really makes sense (in Python at least). It'd be different if there was an abstract/interface LED type, so a single LEDs or a group of LEDs would implement that interface, but in Python that's just done by duck typing.
The real reason for the incompatibility here is a thing in MicroPython where if a type derives from a native type, and the __init__ method of the type doesn't explicitly call super().__init__ it injects a call to the native base's __init__ with the same arguments. (Which in this case is no arguments). So the error is coming from pyb.LED's make_new function which expects an LED number.
So you can technically work around this error by putting super().__init__(1) at the end of your __init__. And that's why you see the toggle still happen, the injected call to init (with no args) happens at the end of your __init__.
I'll come back to a better explanation, but I'm not sure that deriving from LED really makes sense (in Python at least). It'd be different if there was an abstract/interface LED type, so a single LEDs or a group of LEDs would implement that interface, but in Python that's just done by duck typing.
The real reason for the incompatibility here is a thing in MicroPython where if a type derives from a native type, and the __init__ method of the type doesn't explicitly call super().__init__ it injects a call to the native base's __init__ with the same arguments. (Which in this case is no arguments). So the error is coming from pyb.LED's make_new function which expects an LED number.
So you can technically work around this error by putting super().__init__(1) at the end of your __init__. And that's why you see the toggle still happen, the injected call to init (with no args) happens at the end of your __init__.
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Subclass of LED
Unless I'm missing something your code would work if you simply removed the base class. You seem already to be using composition rather than inheritance - which is usually the correct way to work around this MicroPython limitation:
Code: Select all
from pyb import LED
class MyLed:
def __init__(self):
self.led1_obj = LED(1) # composition
self.led2_obj = LED(2)
self.led1_obj.toggle()
self.led2_obj.toggle()
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Subclass of LED
Yes, just eliminating the base class works fine. I haven't seen any documentation on "composition", but I get it (I think). Thanks
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Composition vs Inheritance
Composition is the term in object oriented programming which describes the case where a class constructor creates a bound variable which is an instance of another object:
Foo "has an instance" of Bar. Contrast with inheritance:
Here Foo "is an instance" of Bar.
The MicroPython restriction on subclassing built-in types can usually be overcome using composition.
Code: Select all
class Foo:
def __init__(self):
self.bar = Bar()
Code: Select all
class Foo(Bar):
def __init__(self):
super().__init__()
The MicroPython restriction on subclassing built-in types can usually be overcome using composition.
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.