I don't get why "blink" has to have the parameter "timer" passed to is when "led.toggle()" needs none.
It's the other way around: when the timer calls a callback, it passes the timer that caused the event to the callback function.
That is why the callback function must be able to take a timer parameter.
(The reason why the timer function call facility is designed like this, is because it is useful in majority of cases. Whenever you have callback functions, regardless of the programming language, you'll see them receive the description of the event that caused the call, in some form or another. It's not any kind of requirement or law, just
often practical. Best thought of as "common" or "usual".)
In Python –– I'm not absolutely sure this is relevant to MicroPython, though! –– the number of parameters a function takes is significant: the interpreter will complain if you pass the wrong number of arguments to a function. The way you specify "any unnamed parameters" is
*args (but you can choose any name for the rest-of-the-arguments list, it does not need to be
args; it's just the commonly used name), and "any other named parameters" is
**kwargs (ditto).
In other words, in Python, if you want to write a function that can be called with any parameters at all, it signature is something like
def myfunction(*args, **kwargs):
"""This function can take any arguments"""
# args is a list of unnamed arguments,
# kwargs is a dict of name-value pairs
You can use the above for the callback functions, but really, it is more effort than just looking up the timer documentation, and what it says about the parameters it passes to the callback function, and then just use that.
Wall-of-text and full example time.
This is an example of how such callback facilities actually work, and why the function signature matters. First, let's create a class that takes a callback function and the parameters it will take as an initialization parameter:
class Call:
def __init__(self, func, *args, **kwargs):
self.func = func
self.args = args
self.kwargs = kwargs
def trigger(self):
self.func(self, *self.args, **self.kwargs)
The first parameter it passes is the
Call object (instance) itself that was triggered, that caused the call. Again, it is not included because it is necessary, but because it is often useful. A test program to use the above is simple,
if __name__ == '__main__':
from sys import stderr
example = Call(print, "Hello, world!", file=stderr)
stderr.write("Call instance constructed. Triggering:\n")
example.trigger()
stderr.write("Done.\n")
which shows that because we pass the
print() built-in Python function as the callback function, it will first print the
Call instance, and then "Hello, world!", to standard error.
To use our own callback:
if __name__ == '__main__':
def myfunc(event, message):
print("Callback called with message '%s'" % message)
example = Call(myfunc, "Another")
example.trigger()
which outputs
Callback called with message 'Another'.
Finally, if we do not know the parameters passed, there are multiple different parameter sets, or we just don't care, we can use the
*args, **kwargs notation to get any unnamed parameters in a list and named parameters in a dict:
if __name__ == '__main__':
def myfunc(*args, **kwargs):
print("myfunc received %d unnamed and %d named parameters" % (len(args), len(kwargs)))
example = Call(myfunc, "Second", foo="bar")
example.trigger()
which will output
myfunc received 2 unnamed and 1 named parameters.
Basically, within the function parameter list, the
* prefix means "the rest of the unnamed parameters as a list", and
** means "the rest of the named parameters as a dict". When used elsewhere, the
* prefix means "expand the contents of the list here", and
** "expand the contents of the dict here as a list of name=value pairs".
Now, if we try to use a no-parameter callback,
if __name__ == '__main__':
def myfunc():
print("Triggered!")
example = Call(myfunc)
example.trigger()
instead of getting
Triggered! as the output, a full Python interpreter will abort with a TypeError exception, with the error message being typically
myfunc() takes 0 positional arguments but 1 was given.
Again, this is because in Python, the number of parameters passed to a function matters. If you don't care about the parameters, you don't claim the function takes no parameters, you collect them in
*args and
**kwargs instead.
Hope this helps.
Sorry for the long-windedness, I can't help it.