Page 1 of 1

Extend System Module By Subclassing

Posted: Sun Apr 14, 2019 11:45 pm
by devnull
I realise that this is more of a generic python question rather than micropython specific, but how do I subclass and then add new methods ?

Is it possible to add new methods as well as replace existing ones:

Code: Select all

from network import WLAN
class wlan(WLAN):
    def __init__(self):
        super().__init__()

	def scan(self):
		print('replace original scanning method')
		super().scan()

	def xscan(self):
		print('new scan method using sub method')
		super().scan()

wlan().xscan()
wlan().scan()

Re: Extend a Module By Subclassing

Posted: Mon Apr 15, 2019 5:51 am
by kevinkk525
Theoretically it is but I'd be very careful. The built-in c classes often don't like being subclassed and are not working as expected. An example might be machine.Pin which doesn't conform to a typical python class and makes subclassing kind of impossible.

Re: Extend a Module By Subclassing

Posted: Mon Apr 15, 2019 9:48 am
by pythoncoder
Yes. There is no problem subclassing a class you have created and, in the subclass, adding new methods. But as Kevin says, subclassing built-in types like int, dict or WLAN is not supported by MicroPython - see this doc.

Only subclass a built-in type if it has specifically been designed for this purpose. The only example of which I'm aware is framebuf.

Re: Extend a Module By Subclassing

Posted: Tue Apr 16, 2019 1:33 pm
by tuupola
You could use composition instead of inheritance. Personally I always prefer composition.

Code: Select all

class wlan:
    def __init__(self, station):
        self._station = station

	def scan(self):
		print('replace original scanning method')
		return self._station.scan()

	def xscan(self):
		print('new scan method using sub method')
		return self._station.scan()
Which you could then use with something like:

Code: Select all

from network import WLAN, STA_IF
original = WLAN(STA_IF)
custom = wlan(original)

custom.xscan()
custom.scan()

Re: Extend a Module By Subclassing

Posted: Tue Apr 16, 2019 11:34 pm
by devnull
Hmm. interesting was not aware of the composition approach, but I guess that custom() will not contain all of the original methods and variables from WLAN() in your example, and that I would need to redefine / link them all if required ?

i.e.

Code: Select all

class wlan:
    def __init__(self, station):
        self._station = station
        self.config = station.config
        self.connect = station.connect
        self.isconnected = station.isconnected
        
	def scan(self):
		print('replace original scanning method')
		return self._station.scan()

	def xscan(self):
		print('new scan method using sub method')
		return self._station.scan()

Re: Extend System Module By Subclassing

Posted: Wed Apr 17, 2019 5:11 am
by pythoncoder
Yes, that is the reason why you might prefer inheritance over composition (if it were available). An example is the framebuf class which does allow inheritance. If you write a driver for specific display hardware such that it subclasses framebuf you get a set of fast C graphics primitives; all for zero programming effort and without runtime overhead.

Re: Extend a Module By Subclassing

Posted: Wed Apr 17, 2019 7:57 am
by tuupola
devnull wrote:
Tue Apr 16, 2019 11:34 pm
Hmm. interesting was not aware of the composition approach, but I guess that custom() will not contain all of the original methods and variables from WLAN() in your example, and that I would need to redefine / link them all if required ?
You can use __getattr__ magic. It should work for both attributes and function.

Code: Select all

class wlan:
    def __init__(self, station):
        self._station = station

	def __getattr__(self, name):
            return getattr(self._station, name)
        
	def scan(self):
		print('replace original scanning method')
		return self._station.scan()

	def xscan(self):
		print('new scan method using sub method')
		return self._station.scan()

Re: Extend System Module By Subclassing

Posted: Wed Apr 17, 2019 10:10 am
by devnull
That's very neat, but this does not appear to work:

Code: Select all

from network import WLAN, STA_IF
original = WLAN(STA_IF)
custom = wlan(original)

custom.xscan()
custom.scan()
I have to call:

Code: Select all

custom._station.scan()

Re: Extend System Module By Subclassing

Posted: Wed Apr 17, 2019 1:38 pm
by tuupola
Tested with real device and works for me with ESP32. Note that __getattr__ is called only when accessing an undefined attribute. Here is a bit cleaned up code:

Code: Select all

import network

class wlan:
    def __init__(self, mode):
        self._station = network.WLAN(mode)
        self._station.active(True)

    def __getattr__(self, name):
        return getattr(self._station, name)
Tested from REPL:

Code: Select all

MicroPython ESP32_LoBo_v3.2.24 - 2018-09-06 on ESP32 board with ESP32
Type "help()" for more information.
>>> import network
>>> from wlan import wlan
>>>
>>> wifi = wlan(network.STA_IF)
>>> wifi.scan
<bound_method>
>>> wifi.scan()
[(b'Manny-3BB', b'd\x12l\x00\xf1\xf0', 1, -79, 4, 'WPA_WPA2_PSK', False), (b'Myroom119819', b'\x04OLc7H', 8, -79, 4, 'WPA_WPA2_PSK', False), (b'Fcape1', b'\x03\x17\xd6\xf5s=', 6, -82, 0, 'OPEN', False),... rest removed]