More elegant way of declaring multiple variables at the same time
Solution 1:
a, b, c, d, e, g, h, i, j = (True,)*9
f = False
Solution 2:
As others have suggested, it's unlikely that using 10 different local variables with Boolean values is the best way to write your routine (especially if they really have one-letter names :)
Depending on what you're doing, it may make sense to use a dictionary instead. For example, if you want to set up Boolean preset values for a set of one-letter flags, you could do this:
>>> flags = dict.fromkeys(["a", "b", "c"], True)
>>> flags.update(dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}
If you prefer, you can also do it with a single assignment statement:
>>> flags = dict(dict.fromkeys(["a", "b", "c"], True),
... **dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}
The second parameter to dict
isn't entirely designed for this: it's really meant to allow you to override individual elements of the dictionary using keyword arguments like d=False
. The code above blows up the result of the expression following **
into a set of keyword arguments which are passed to the called function. This is certainly a reliable way to create dictionaries, and people seem to be at least accepting of this idiom, but I suspect that some may consider it Unpythonic. </disclaimer>
Yet another approach, which is likely the most intuitive if you will be using this pattern frequently, is to define your data as a list of flag values (True
, False
) mapped to flag names (single-character strings). You then transform this data definition into an inverted dictionary which maps flag names to flag values. This can be done quite succinctly with a nested list comprehension, but here's a very readable implementation:
>>> def invert_dict(inverted_dict):
... elements = inverted_dict.iteritems()
... for flag_value, flag_names in elements:
... for flag_name in flag_names:
... yield flag_name, flag_value
...
>>> flags = {True: ["a", "b", "c"], False: ["d", "e"]}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}
The function invert_dict
is a generator function. It generates, or yields — meaning that it repeatedly returns values of — key-value pairs. Those key-value pairs are the inverse of the contents of the two elements of the initial flags
dictionary. They are fed into the dict
constructor. In this case the dict
constructor works differently from above because it's being fed an iterator rather than a dictionary as its argument.
Drawing on @Chris Lutz's comment: If you will really be using this for single-character values, you can actually do
>>> flags = {True: 'abc', False: 'de'}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}
This works because Python strings are iterable, meaning that they can be moved through value by value. In the case of a string, the values are the individual characters in the string. So when they are being interpreted as iterables, as in this case where they are being used in a for loop, ['a', 'b', 'c']
and 'abc'
are effectively equivalent. Another example would be when they are being passed to a function that takes an iterable, like tuple
.
I personally wouldn't do this because it doesn't read intuitively: when I see a string, I expect it to be used as a single value rather than as a list. So I look at the first line and think "Okay, so there's a True flag and a False flag." So although it's a possibility, I don't think it's the way to go. On the upside, it may help to explain the concepts of iterables and iterators more clearly.
Defining the function invert_dict
such that it actually returns a dictionary is not a bad idea either; I mostly just didn't do that because it doesn't really help to explain how the routine works.
Apparently Python 2.7 has dictionary comprehensions, which would make for an extremely concise way to implement that function. This is left as an exercise to the reader, since I don't have Python 2.7 installed :)
You can also combine some functions from the ever-versatile itertools module. As they say, There's More Than One Way To Do It. Wait, the Python people don't say that. Well, it's true anyway in some cases. I would guess that Guido hath given unto us dictionary comprehensions so that there would be One Obvious Way to do this.
Solution 3:
Use a list/dictionary or define your own class to encapsulate the stuff you're defining, but if you need all those variables you can do:
a = b = c = d = e = g = h = i = j = True
f = False
Solution 4:
This is an elaboration on @Jeff M's and my comments.
When you do this:
a, b = c, d
It works with tuple packing and unpacking. You can separate the packing and unpacking steps:
_ = c, d
a, b = _
The first line creates a tuple called _
which has two elements, the first with the value of c
and the second with the value of d
. The second line unpacks the _
tuple into the variables a
and b
. This breaks down your one huge line:
a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True, True, True, True
Into two smaller lines:
_ = True, True, True, True, True, False, True, True, True, True
a, b, c, d, e, f, g, h, i, j = _
It will give you the exact same result as the first line (including the same exception if you add values or variables to one part but forget to update the other). However, in this specific case, yan's answer is perhaps the best.
If you have a list of values, you can still unpack them. You just have to convert it to a tuple first. For example, the following will assign a value between 0 and 9 to each of a
through j
, respectively:
a, b, c, d, e, f, g, h, i, j = tuple(range(10))
EDIT: Neat trick to assign all of them as true except element 5 (variable f
):
a, b, c, d, e, f, g, h, i, j = tuple(x != 5 for x in range(10))