Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is foo(*arg, x) not allowed in Python?

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?

EDIT: Specific Questions

Why are multiple *arg expansions not allowed in function calls?

Why are positional arguments not allowed after *arg expansions?

like image 538
Chris Avatar asked Jun 17 '11 14:06

Chris


People also ask

What is* args in Python?

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.

How to pass kwargs in Python?

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 ( ** ).

How do you access args Python?

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.

What is Kwargs in Python stackoverflow?

**kwargs = dictionary - whose keys become separate keyword arguments and the values become values of these arguments.


1 Answers

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.

like image 186
ironchefpython Avatar answered Sep 27 '22 21:09

ironchefpython