Reputation: 545
I am trying to implement a callback system in Python that is similar to how JavaScript can have different numbers of parameters in its callbacks. Ideally, I want to achieve this without using *args
or **kwargs
in the parameters of my callbacks.
What I want is something that looks roughly like this:
def callback1(val):
print(val)
def callback2(x, y):
print(x, y)
def callback3(a, b, c):
print(a, b, c)
def foo(callback):
callback(1, 2, 3) # Always has 3 arguments to pass
foo(callback1) # Fails. Should print "1"
foo(callback2) # Fails. Should print "1 2"
foo(callback3) # Ok. Prints "1 2 3"
Perhaps a more verbose way of putting it would be:
# num_params() method isn't real (that I know of), but this is an
# inelegant example of how the callbacks might work if it were
def foo2(callback):
if num_params(callback) == 1:
callback(1)
elif num_params(callback) == 2:
callback(1, 2)
elif num_params(callback) == 3:
callback(1, 2, 3)
I don't want to use *args
or **kwargs
in each callback (unless this isn't possible any other way) like the following:
# This is just SO ugly
def callback1(*args):
print(args[0])
def callback2(*args):
print(args[0], args[1])
def callback3(*args):
print(args[0], args[1], args[2])
This is relatively common in JavaScript. For example, one can supply the callback of a .forEach()
function with 1, 2, or 3 arguments:
let myArray = [1, 2, 3, 4]
// Valid
myArray.forEach((element) => {
// Do stuff with the element only
});
// Valid
myArray.forEach((element, index) => {
// Do stuff with the element AND the index
});
// Valid
myArray.forEach((element, index, array) => {
// Do stuff with the element, index and the whole array
});
However, despite my best efforts in Google searching, I have no idea how to implement this in Python (or even in JavaScript for that matter, but that's beside the point; I hope this doesn't come back to bite me).
I would very much like to know if this is possible in Python and/or what the proper term is for this coding technique.
Upvotes: 1
Views: 1585
Reputation: 661
What's wrong with args and kwargs? It is the pythonic way to do that. Python is not JavaScript. If you do not like accessing args by indexes like args[0]
, args[1]
, etc, you could just define some args like usual, and rest (unused args) - in *args
:
def callback1(a, *args):
print(a)
def callback2(a, b, *args):
print(a, b)
def callback3(a, b, c):
print(a, b, c)
Also you can unpack them in the function:
def callback1(*args):
a, *rest = args
print(a)
It makes it more verbose inside, but same definition for all callbacks.
Also it's common to name variables, you are not going to use with _
(underscore) instead of args
, rest
, etc.:
def callback1(a, *_):
print(a)
def callback1(*args):
a, *_ = args
print(a)
Upvotes: 2
Reputation: 59184
You can define all your callback functions using the same number of arguments, i.e.:
def callback1(val, b=None, c=None):
print(val)
def callback2(x, y, c=None):
print(x, y)
def callback3(a, b, c):
print(a, b, c)
Alternatively you can unpack *args
within functions:
def callback1(*args):
val, _, _ = args
print(val)
def callback2(*args):
x, y, _ = args
print(x, y)
def callback3(*args):
a, b, c = args
print(a, b, c)
Finally, you can get creative using functools.partial
.
Upvotes: 2