Builtin function to apply single expression with multiple variables

Is there an existing Python builtin function which assigns two or more variables and returns multiple values upon assigning a single expression? For example:


attrs, patterns, weight = [] * 3

is the same as:

attrs, patterns, weight = [], [], []
- - Source


answered 4 week ago user2357112 #1

The best existing syntax for that is

attrs, patterns, weight = [[] for i in range(3)]

which isn't really an improvement over [], [], []. It has an advantage for complex expressions, though.

If you wanted a function, you'd run into the problem that Python functions take objects, not expressions. A function can't evaluate its argument expressions repeatedly. If you wanted to write a function, you'd have to wrap the expression in a lambda or something:

def n_times(constructor, n):
    return [constructor() for i in range(n)]

attrs, patterns, weight = n_times(lambda: [], 3)
# or
attrs, patterns, weight = n_times(list, 3)

There are a few tempting but wrong options:

# Mistake
attrs = patterns = weight = []
# Also a mistake
attrs, patterns, weight = [[]]*3

which assign the same list to each variable instead of making separate lists, because Python assignment doesn't make copies, and list multiplication doesn't copy the elements, only references to the elements.

answered 4 week ago Chiheb Nexus #2

If you want to have the behaviour you're trying to have, you can create a custom object that behaves like this expression: var1, var2, var3 = __OBJECT__ * 3

Here is an example:

from collections.abc import Iterable

class Custom:   
     def __init__(self, initial=[]):
         if not isinstance(initial, Iterable):
             raise ValueError()
         self.initial = initial
         self.args = initial

     def __mul__(self, args):
         self.args = [self.initial[:] for _ in range(args)]
         return self.args

     def __iter__(self):
         for _ in range(len(self.args)):
             yield self.initial

     def __repr__(self):
         return '{}'.format(list(self))


$> a, b, c = Custom() * 3
$> print(a, b, c) # [] [] []
$> id(a) == id(b) == id(c) # False

$> a, b, c = Custom(()) * 3
$> print(a, b, c) # () () ()
$> id(a) == id(b) == id(c) # True

answered 1 week ago Joe P #3

a = b = c = []

All variables are independently set to the same value. (Caution: the same mutable object, but that is true of any multiple assignment in Python.)

See the documentation of the assignment statement - multiple target_list "=" sections are allowed.

An assignment statement evaluates the expression list [...] and assigns the single resulting object to each of the target lists, from left to right.

This was a surprise to me when I first tried it in an immediate session! But it works just as you'd expect.

comments powered by Disqus