kopia lustrzana https://github.com/peterhinch/micropython-samples
Update build scripts. Add functor/singleton doc.
rodzic
8caf7a9c2f
commit
1e88ebd417
|
@ -0,0 +1,79 @@
|
|||
# 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.
|
||||
|
||||
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.
|
||||
|
||||
```python
|
||||
def singleton(cls):
|
||||
instance = None
|
||||
def getinstance(*args, **kwargs):
|
||||
nonlocal instance
|
||||
if instance is None:
|
||||
instance = cls(*args, **kwargs)
|
||||
return instance
|
||||
return getinstance
|
||||
|
||||
@singleton
|
||||
class MySingleton:
|
||||
def __init__(self, arg):
|
||||
self.state = arg
|
||||
print('In __init__', arg)
|
||||
|
||||
def foo(self, arg):
|
||||
print('In foo', arg + self.state)
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
is a private instance, initially `None`. The function checks if the instance is
|
||||
`None`. If so it instantiates the object and assigns it to the instance. In all
|
||||
cases it returns the instance.
|
||||
|
||||
Both have similar logic. The decorator avoids the need for a separate module.
|
||||
|
||||
# Functor class decorator
|
||||
|
||||
The term "functor" derives from "function constructor". It is a function-like
|
||||
object which can retain state. Like singletons the aim is to avoid globals: the
|
||||
state is contained in the functor instance.
|
||||
|
||||
```python
|
||||
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 MyFunctor:
|
||||
def __init__(self, arg):
|
||||
self.state = arg
|
||||
print('In __init__', arg)
|
||||
|
||||
def __call__(self, arg):
|
||||
print('In __call__', arg + self.state)
|
||||
|
||||
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).
|
|
@ -0,0 +1,44 @@
|
|||
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
|
||||
|
||||
def singleton(cls):
|
||||
instance = None
|
||||
def getinstance(*args, **kwargs):
|
||||
nonlocal instance
|
||||
if instance is None:
|
||||
instance = cls(*args, **kwargs)
|
||||
return instance
|
||||
return getinstance
|
||||
|
||||
@singleton
|
||||
class MySingleton:
|
||||
def __init__(self, arg):
|
||||
self.state = arg
|
||||
print('In __init__', arg)
|
||||
|
||||
def foo(self, arg):
|
||||
print('In foo', arg + self.state)
|
||||
|
||||
ms = MySingleton(42) # prints 'In __init__ 42'
|
||||
a = MySingleton(99) # No output: assign existing instance to a
|
||||
a.foo(5) # prints 'In foo 47': original state + 5
|
||||
|
||||
|
||||
@functor
|
||||
class MyFunctor:
|
||||
def __init__(self, arg):
|
||||
self.state = arg
|
||||
print('In __init__', arg)
|
||||
|
||||
def __call__(self, arg):
|
||||
print('In __call__', arg + self.state)
|
||||
|
||||
MyFunctor(42) # prints 'In __init__ 42'
|
||||
MyFunctor(5) # 'In __call__ 47'
|
Ładowanie…
Reference in New Issue