Initialize a list of objects in Python
Solution 1
There isn't a way to implicitly call an Object()
constructor for each element of an array like there is in C++ (recall that in Java, each element of a new array is initialised to null
for reference types).
I would say that your list comprehension method is the most Pythonic:
lst = [Object() for i in range(100)]
If you don't want to step on the lexical variable i
, then a convention in Python is to use _
for a dummy variable whose value doesn't matter:
lst = [Object() for _ in range(100)]
For an equivalent of the similar construct in Java, you can of course use *
:
lst = [None] * 100
Solution 2
You should note that Python's equvalent for Java code (creating array of 100 null references to Object):
Object arr = new Object[100];
or C++ code:
Object **arr = new Object*[100];
is:
arr = [None]*100
not:
arr = [Object() for _ in range(100)]
The second would be the same as Java's:
Object arr = new Object[100];
for (int i = 0; i < arr.lenght; i++) {
arr[i] = new Object();
}
In fact Python's capabilities to initialize complex data structures are far better then Java's.
Note: C++ code:
Object *arr = new Object[100];
would have to do as much work as Python's list comprehension:
allocate continuous memory for 100 Objects
call Object::Object() for each of this Objects
And the result would be a completely different data structure.
Solution 3
I think the list comprehension is the simplest way, but, if you don't like it, it's obviously not the only way to obtain what you desire -- calling a given callable 100 times with no arguments to form the 100 items of a new list. For example, itertools
can obviously do it:
>>> import itertools as it
>>> lst = list(it.starmap(Object, it.repeat((), 100)))
or, if you're really a traditionalist, map
and apply
:
>>> lst = map(apply, 100*[Object], 100*[()])
Note that this is essentially the same (tiny, both conceptually and actually;-) amount of work it would take if, instead of needing to be called without arguments, Object
needed to be called with one argument -- or, say, if Object
was in fact a function rather than a type.
From your surprise that it might take "as much as a list comprehension" to perform this task, you appear to think that every language should special-case the need to perform "calls to a type, without arguments" over other kinds of calls to over callables, but I fail to see what's so crucial and special about this very specific case, to warrant treating it differently from all others; and, as a consequence, I'm pretty happy, personally, that Python doesn't single this one case out for peculiar and weird treatment, but handles just as regularly and easily as any other similar use case!-)
bradreaves
Updated on August 28, 2020Comments
-
bradreaves almost 4 years
I'm a looking to initialize an array/list of objects that are not empty -- the class constructor generates data. In C++ and Java I would do something like this:
Object lst = new Object[100];
I've dug around, but is there a Pythonic way to get this done?
This doesn't work like I thought it would (I get 100 references to the same object):
lst = [Object()]*100
But this seems to work in the way I want:
lst = [Object() for i in range(100)]
List comprehension seems (intellectually) like "a lot" of work for something that's so simple in Java.
-
inspectorG4dget over 14 yearsI feel that you are overcomplicating things. Something as simple as this will NOT require the import of other modules
-
bradreaves over 14 yearsGood point about the special case -- I guess I hadn't thought about it from that point of view. That map line is really neat -- I haven't played with maps yet, so I'll have to play with it.
-
Alex Martelli over 14 yearsAh but @Inspector, you see, the map/apply solution doesn't require any import, but that doesn't make it any less complicated than the itertools one: it just happens to use old stuff which happened to be placed in builtins many, many years ago, while itertools is a newer idea and was properly put in its own module of the standard library.
apply
is gone in Python 3, andmap
changed. So, you see: your perceptions of what's complicated (based on such a totally inappropriate criterion as using import or not!) are really entirely, fundamentally wrong and misplaced. -
Serge Stroobandt over 8 years@orip In Python 3,
range()
does whatxrange()
used to do andxrange()
does not exist. If you want to write code that will run on both Python 2 and Python 3, you cannot usexrange()
. -
orip over 8 years@SergeStroobandt fair enough, although there are more significant differences between 2 and 3 and I'd suggest a different approach for compatibility, e.g target 3 explicitly or maintain compatibility with 2to3, instead of surprise Python2 users with potentially huge memory allocations
-
Pete P about 7 yearsit's interesting that in my Eclipse environment, the top list comprehension way was giving me warnings about the unused variable i and when I used the underscore, it stopped warning me about this. I'm wondering, does it actually change what happens? Does Python know the underscore is a dummy variable that is unused and therefore perform faster?
-
Greg Hewgill about 7 years@PeteP: No, using the underscore does not change what Python does. (You can check this yourself by timing the code with and without the underscore.) You're just seeing that using the underscore changes the behaviour of Eclipse.