Look at the following example
point = (1, 2) size = (2, 3) color = 'red' class Rect(object): def __init__(self, x, y, width, height, color): pass
It would be very tempting to call:
Rect(*point, *size, color)
Possible workarounds would be:
Rect(point[0], point[1], size[0], size[1], color) Rect(*(point + size), color=color) Rect(*(point + size + (color,)))
But why is Rect(*point, *size, color)
not allowed, is there any semantic ambiguity or general disadvantage you could think of?
Why are multiple *arg expansions not allowed in function calls?
Why are positional arguments not allowed after *arg expansions?
Python has *args which allow us to pass the variable number of non keyword arguments to function. In the function, we should use an asterisk * before the parameter name to pass variable length arguments.
Kwargs allow you to pass keyword arguments to a function. They are used when you are not sure of the number of keyword arguments that will be passed in the function. Kwargs can be used for unpacking dictionary key, value pairs. This is done using the double asterisk notation ( ** ).
To access command-line arguments from within a Python program, first import the sys package. You can then refer to the full set of command-line arguments, including the function name itself, by referring to a list named argv. In either case, argv refers to a list of command-line arguments, all stored as strings.
**kwargs = dictionary - whose keys become separate keyword arguments and the values become values of these arguments.
I'm not going to speak to why multiple tuple unpacking isn't part of Python, but I will point out that you're not matching your class to your data in your example.
You have the following code:
point = (1, 2) size = (2, 3) color = 'red' class Rect(object): def __init__(self, x, y, width, height, color): self.x = x self.y = y self.width = width self.height = height self.color = color
but a better way to express your Rect object would be as follows:
class Rect: def __init__(self, point, size, color): self.point = point self.size = size self.color = color r = Rect(point, size, color)
In general, if your data is in tuples, have your constructor take tuples. If your data is in a dict, have your constructor take a dict. If your data is an object, have your constructor take an object, etc.
In general, you want to work with the idioms of the language, rather than try to work around them.
EDIT Seeing how popular this question is, I'll give you an decorator that allows you to call the constructor however you like.
class Pack(object): def __init__(self, *template): self.template = template def __call__(self, f): def pack(*args): args = list(args) for i, tup in enumerate(self.template): if type(tup) != tuple: continue for j, typ in enumerate(tup): if type(args[i+j]) != typ: break else: args[i:i+j+1] = [tuple(args[i:i+j+1])] f(*args) return pack class Rect: @Pack(object, (int, int), (int, int), str) def __init__(self, point, size, color): self.point = point self.size = size self.color = color
Now you can initialize your object any way you like.
r1 = Rect(point, size, color) r2 = Rect((1,2), size, color) r3 = Rect(1, 2, size, color) r4 = Rect((1, 2), 2, 3, color) r5 = Rect(1, 2, 2, 3, color)
While I wouldn't recommend using this in practice (it violates the principle that you should have only one way to do it), it does serve to demonstrate that there's usually a way to do anything in Python.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With