Reputation:
I have gone through these questions,
- Python assigning multiple variables to same value? list behavior
concerned with tuples, I want just variables may be a string, integer or dictionary- More elegant way of declaring multiple variables at the same time
The question has something I want to ask, but the accepted answer is much complex
so what I'm trying to achieve,
I declare variables as follows, and I want to reduce these declarations to as less line of code as possible.
details = None
product_base = None
product_identity = None
category_string = None
store_id = None
image_hash = None
image_link_mask = None
results = None
abort = False
data = {}
What is the simplest, easy to maintain ?
Upvotes: 53
Views: 96458
Reputation: 23
This way:
( var1, var2, var3, var3, var4,
var5, var6 ) = ( [None] * 6 )
The parenthesis are important if you want it to be multiline due to several variables and/or large names. Also do not forget to put the "None" between square brackets.
Upvotes: 0
Reputation: 12229
After having participated in the discussion under @belgacea's answer, I'd like to post the variant of that answer that I think is the best:
import copy
def duplicate(value, n):
return [copy.deepcopy(value) for _ in range(n)]
a, b, c = duplicate([0], 3)
o, p, q, r, s = duplicate(None, 5)
t, u = duplicate(False, 2)
v, w, x = duplicate({}, 3)
y, z = duplicate(MyClass(), 2)
In all cases, we're guaranteed by deepcopy()
that mutable objects are not shared among the different variables initialized together, which is the important gotcha to avoid.
But I've simplified the code to its simplest expression, taking advantage of the fact that deepcopy
is already well optimized to do a shallow copy when its input is immutable. I've tested this with strings and tuples, and if x
is recursively immutable, e.g., x = ((1,2),"foo")
, then x is copy.deepcopy(x)
returns True, so there's no benefit in trying to avoid calling deepcopy
on values that don't need a deep copy.
I've also changed the signature and name of the function to something that I think will make better self-documenting code where it is used.
Upvotes: 1
Reputation: 1164
A mix of previous answers :
from copy import deepcopy
def default(number, value = None):
if type(value) is dict or object:
return [deepcopy(value) for _ in range(number)]
else:
return [value] * number
o, p, q, r, s = default(5)
t, u = default(2, false)
v, w, x = default(3, {})
class GPU:
def __init__(self, m, p):
self.model = m
self.price = p
rtx_3080 = GPU("RTX 3080", 99999)
y, z = default(2, rtx_3080)
Edit:
Tried to optimize deepcopy call by better handling mutable variables with pandas/numpy types as well. Might have missed some other ones. If someone find a better way to check for mutability, feel free to share. Althought, this maybe over-engineering whatever your use case is...
import builtins
from copy import deepcopy
from numbers import Number
from pandas import api, DataFrame
mutables = (dict, list, set, DataFrame)
immutables = (str, tuple, frozenset, Number)
def is_built_in_type(var):
return type(var).__name__ in dir(builtins)
def is_mutable(var):
return var is not None and (api.types.is_list_like(var) or isinstance(var, mutables) or not is_built_in_type(var))
def is_immutable(var):
return var is None or isinstance(var, immutables)
def default(number, value=None):
if is_mutable(value):
return [deepcopy(value) for _ in range(number)]
elif is_immutable(value):
return [value] * number
else:
raise ValueError("Unexpected value type")
a, b, c, d, e = default(5)
f, g, h = default(3, False)
i, j = default(2, "False")
k, l, m, n = default(4, (3, 2, 1))
o, p = default(2, 3.14159265358979)
q, r, s = default(3, [1, 2, 3])
t, u = default(2, {})
v, w, x = default(3, DataFrame({'col1': [7, 13, 42, 73, 666], 'col2': [1, 0.6, 2, 1.4, 0.3]}))
class GPU:
def __init__(self, m, p):
self.model = m
self.price = p
rtx_3080 = GPU("RTX 3080", 99999)
y, z = default(2, rtx_3080)
Upvotes: 2
Reputation: 409
(
details,
producy_base,
product_identity,
category_string,
store_id,
image_hash,
image_link_mask,
results,
) = (None, None, None, None, None, None, None, None)
abort = False
data = {}
That's how I do.
Upvotes: 18
Reputation: 156
This does not directly answer the question, but it is related -- I use an instance of an empty class to group similar attributes, so I do not have to clutter up my init method by listing them all.
class Empty:
pass
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.w = Empty() # widgets
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
self.w.entry = tk.Entry(self, bg="orange", fg="black", font=FONT)
What is the difference between SimpleNamespace and empty class definition?
Upvotes: -2
Reputation: 1297
I have a one-line lambda function I use that helps me out with this.
nones = lambda n: [None for _ in range(n)]
v, w, x, y, z = nones(5)
The lambda is the same thing as this.
def nones(n):
return [None for _ in range(n)]
Upvotes: 7
Reputation: 1054
I agree with the other answers but would like to explain the important point here.
None object is singleton object. How many times you assign None object to a variable, same object is used. So
x = None
y = None
is equal to
x = y = None
but you should not do the same thing with any other object in python. For example,
x = {} # each time a dict object is created
y = {}
is not equal to
x = y = {} # same dict object assigned to x ,y. We should not do this.
Upvotes: 81
Reputation: 1391
First of all I would advice you not to do this. It's unreadable and un-Pythonic. However you can reduce the number of lines with something like:
details, product_base, product_identity, category_string, store_id, image_hash, image_link_mask, results = [None] * 8
abort = False
data = {}
Upvotes: 37