kopia lustrzana https://github.com/peterhinch/micropython-samples
README improvements.
rodzic
61d312be15
commit
2399918b38
10
README.md
10
README.md
|
@ -227,12 +227,10 @@ may readily be added as required.
|
|||
Two simple class decorators for objects useful in hardware interfacing.
|
||||
Documented [here](./functor_singleton/README.md).
|
||||
|
||||
Singletons denote classes for which only a single instance will ever occur.
|
||||
They are contentious in some circles, on the grounds that the single instance
|
||||
guarantee may be violated in a specification change. They can be useful in
|
||||
hardware contexts where a chip design is unlikely suddenly to change.
|
||||
Singletons denoting hardware interfaces avoid globals and the need to pass
|
||||
references around.
|
||||
Singletons denote classes for which only a single instance can ever occur.
|
||||
They can be useful for hardware interface classes. Their use avoids the need
|
||||
for a global instance: the sole instance may be retrieved efficiently from
|
||||
anywhere in the code.
|
||||
|
||||
A functor is a class which is accessed via function call syntax. There is only
|
||||
one instance, like a singleton. Initial access calls the constructor, with
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
# Singletons and Functors
|
||||
|
||||
These closely related concepts describe classes which support only a single
|
||||
instance. They share a common purpose of avoiding the need for global data by
|
||||
providing a callable capable of retaining state and whose scope may be that of
|
||||
the module.
|
||||
|
||||
In both cases implementation is via very similar class decorators.
|
||||
|
||||
# Singleton class decorator
|
||||
|
||||
A singleton is a class which has only one instance. IT gurus debate whether
|
||||
they should be used, mainly on the grounds that project aims can change: a need
|
||||
for multiple instances may arise later. I would argue that singleton classes
|
||||
have merit in defining interfaces to hardware objects. You can be sure that
|
||||
(for example) a Pyboard D will only have one RTC instance.
|
||||
A singleton is a class with only one instance. Some IT gurus argue against them
|
||||
on the grounds that project aims can change: a need for multiple instances may
|
||||
arise later. My view is that they have merit in defining interfaces to hardware
|
||||
objects. You might be quite certain that your brometer will have only one
|
||||
pressure sensor.
|
||||
|
||||
The advantage of a singleton is that it removes the need for a global instance
|
||||
or for passing an instance between functions. The sole instance is retrieved at
|
||||
any point in the code using constructor call syntax.
|
||||
or for passing an instance between functions. The sole instance is efficiently
|
||||
retrieved at any point in the code using function call syntax.
|
||||
|
||||
```python
|
||||
def singleton(cls):
|
||||
|
@ -33,8 +42,8 @@ ms = MySingleton(42) # prints 'In __init__ 42'
|
|||
x = MySingleton() # No output: assign existing instance to x
|
||||
x.foo(5) # prints 'In foo 47': original state + 5
|
||||
```
|
||||
The first instantiation sets the object's initial state. Thereafter
|
||||
'instantiations' retrieve the original object.
|
||||
The first call instantiates the object and sets its initial state. Subsequent
|
||||
calls retrieve the original object.
|
||||
|
||||
There are other ways of achieving singletons. One is to define a (notionally
|
||||
private) class in a module. The module API contains an access function. There
|
||||
|
@ -73,7 +82,49 @@ class MyFunctor:
|
|||
MyFunctor(42) # prints 'In __init__ 42'
|
||||
MyFunctor(5) # 'In __call__ 47'
|
||||
```
|
||||
A use case is in asynchronous programming. The constructor launches a task:
|
||||
this will only occur once. Subsequent calls might alter the behaviour of that
|
||||
task. An example may be found
|
||||
[in the Latency class](https://github.com/peterhinch/micropython-async/blob/master/lowpower/rtc_time.py).
|
||||
A use case is in asynchronous programming. The constructor launches a
|
||||
continuously running task. Subsequent calls alter the behaviour of that task.
|
||||
The following simple example has the task waiting for a period which can be
|
||||
changed at runtime:
|
||||
|
||||
```python
|
||||
import uasyncio as asyncio
|
||||
import pyb
|
||||
|
||||
def functor(cls):
|
||||
instance = None
|
||||
def getinstance(*args, **kwargs):
|
||||
nonlocal instance
|
||||
if instance is None:
|
||||
instance = cls(*args, **kwargs)
|
||||
return instance
|
||||
return instance(*args, **kwargs)
|
||||
return getinstance
|
||||
|
||||
@functor
|
||||
class FooFunctor:
|
||||
def __init__(self, led, interval):
|
||||
self.led = led
|
||||
self.interval = interval
|
||||
asyncio.create_task(self._run())
|
||||
|
||||
def __call__(self, interval):
|
||||
self.interval = interval
|
||||
|
||||
async def _run(self):
|
||||
while True:
|
||||
await asyncio.sleep_ms(self.interval)
|
||||
# Do something useful here
|
||||
self.led.toggle()
|
||||
|
||||
def go_fast(): # FooFunctor is available anywhere in this module
|
||||
FooFunctor(100)
|
||||
|
||||
async def main():
|
||||
FooFunctor(pyb.LED(1), 500)
|
||||
await asyncio.sleep(3)
|
||||
go_fast()
|
||||
await asyncio.sleep(3)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
|
Ładowanie…
Reference in New Issue