Based on the other answers, I think the cleanest solutions are
#Handles None return from get_list
for item in get_list() or []:
pass #do something
or the comprehension equiv
result = [item*item for item in get_list() or []]
Answer from Tom Leys on Stack Overflowpython - For loop through the list unless empty? - Stack Overflow
for/empty loop condition in python - Stack Overflow
python - Would a for loop over an empty list actually spend time / resources? - Stack Overflow
language design - Why don't empty iterables in python raise Exceptions when you try to iterate over them - Software Engineering Stack Exchange
images = [ ] for filename in filenames:
Because otherwise without it, if you either refer to it in the loop, it won't exist so you'll get an error. Or if you define it in the loop, you'll redefine it every iteration, destroying all the progress added to it from every previous iteration.
Why do you need to hold an empty cup before pouring water into it?
Based on the other answers, I think the cleanest solutions are
#Handles None return from get_list
for item in get_list() or []:
pass #do something
or the comprehension equiv
result = [item*item for item in get_list() or []]
Use a list comprehension:
def do_something(x):
return x**2
things = []
result = [do_something(x) for x in things]
print result # []
things = [1, 2, 3]
result = [do_something(x) for x in things]
print result # [1, 4, 9]
You'll have to stick with the if statement, but it can be simplified:
for x in my_list:
doSomething()
if not my_list:
print "my_list is empty"
since my_list is empty, the for loop never executes the loop portion, and an empty list is False in a boolean context.
if you are sure that the iterator is not returning a specific value, say None or False, then you can
x = False
for x in my_list:
doSomething(x)
if x is False:
print "my_list is empty"
Not my code, but if we look here, we see that time is used to create this "empty list".
% python -mtimeit "l=[]"
10000000 loops, best of 3: 0.0711 usec per loop
% python -mtimeit "l=list()"
1000000 loops, best of 3: 0.297 usec per loop
As far as actually iterating through the list, yes, this costs resources as well. The interpretter has to at least know that the list is empty, so it must go into the memory location to see that it is empty.
If you're asking if the Python interpreter is able to optimize by skipping the loop entirely, I think the answer is no. If you look at bytecode for iteration over an empty list, all the loop setup steps are still done and bytecode is generated for the code inside the loop (although it won't actually be executed):
import dis
def run_empty_loop():
a = []
for item in a:
x = 1 + 1
dis.dis(run_empty_loop)
2 0 BUILD_LIST 0
3 STORE_FAST 0 (a)
3 6 SETUP_LOOP 20 (to 29)
9 LOAD_FAST 0 (a)
12 GET_ITER
>> 13 FOR_ITER 12 (to 28)
16 STORE_FAST 1 (item)
4 19 LOAD_CONST 2 (2)
22 STORE_FAST 2 (x)
25 JUMP_ABSOLUTE 13
>> 28 POP_BLOCK
>> 29 LOAD_CONST 0 (None)
32 RETURN_VALUE
The thing that I think you're missing here is that the StopIteration is what actually makes the for loop stop. This is why you can write custom iterators that work with Python's for loop transparently. It doesn't do any checking to see if the iterator is empty, and the for loop does not keep track of of the iterator's state. This is an effect of the iterator protocol, and was an intentional choice in the language design. You can read more about the iterator protocol on Python's docs site if you want to.
It also makes more sense if you think about the number of items in e.g. your list corresponding directly to the number of times your loop is executed.
-----------------------------------|
| No. of items | No. times executed|
------------------------------------
| 5 | 5 |
| 4 | 4 |
| 3 | 3 |
| 2 | 2 |
| 1 | 1 |
| 0 | 0 |
------------------------------------
If the for loop special-cased an empty iterable, this invariant would be lost.
It would also complicate the protocol on writing custom iterators, because you would have to have an extra method to signal to the for loop that your iterable is empty before the iteration began.
Here's a (stupid) example of a custom iterator that always acts like it's empty:
class EmptyIterator():
def __iter__(self): return self
def __next__(self): raise StopIteration
for blah in EmptyIterator():
print('this is never reached')
try:
next(EmptyIterator())
except StopIteration:
print('Oh hi, I was empty so I raised this Exception for you.')
This is odd to me. Why should an empty collection be treated any differently?
Forcing the programmer to check if the collection is empty before doing things to it would be a widespread, problematic sort of burden. Worse, an empty collection is in no way exceptional.
Personally, I would rather have the occasional bug where a no-op happened because I forgot to check for the rare case where I wanted different behavior on an empty collection rather than the occasional bug where an exception crashes my app because I forgot to say if empty, do nothing everywhere I wanted that common, expected behavior.
I mean, do you think printing empty strings should throw exceptions?
Is there any reason you don't just use the range() builtin function?
>>> for t in range(5+1): print t, t/10.
0 0.0
1 0.1
2 0.2
3 0.3
4 0.4
5 0.5
I don't see that you need to form the list. But if you do, use a list comprehension :
[(t, t/10.) for t in range(5+1)]
[(0, 0.0), (1, 0.1), (2, 0.2), (3, 0.3), (4, 0.4), (5, 0.5)]
Actually we should use enumerate() as @Amit says:
for t, tval in enumerate(t/10. for t in range(5+1)): print t,tval
...
0 0.0
1 0.1
2 0.2
3 0.3
4 0.4
5 0.5
But in fact it looks like you want to start from 0.1, not 0.0. So you use the optional second arg to enumerate():
for t, tval in enumerate((t/10. for t in range(1,5+1)), 1): print t,tval
...
1 0.1
2 0.2
3 0.3
4 0.4
5 0.5
Use enumerate to avoid counter:
for i, t in enumerate(iteration_time):
print i+1, t
1 0.1
2 0.2
3 0.3
4 0.4
5 0.5
This should help you understand. An attempt to iterate manually over a list:
In [349]: x = iter([1, 2, 3])
In [350]: next(x)
Out[350]: 1
In [351]: next(x)
Out[351]: 2
In [352]: next(x)
Out[352]: 3
In [353]: next(x)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-353-5e4e57af3a97> in <module>()
----> 1 next(x)
StopIteration:
Meanwhile, an empty list throws a StopIteration immediately:
In [354]: x = iter([])
In [355]: next(x)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-355-5e4e57af3a97> in <module>()
----> 1 next(x)
StopIteration:
This exact thing happens in the for loop, iterating over each element until a StopIteration exception is reached. If you have an empty list, you have nothing to iterate over:
In [356]: for i in [1, 2, 3]:
...: print(i)
...:
1
2
3
In [357]: for i in []:
...: print(i)
...:
You are misunderstanding the use of for, it goes through all the elements of the array, and what you tell it to do, if the array is empty, it doesn't executes anything, and the variable r is not used, look:
arr = []
for r in arr:
print(r)
print("Why?")
Doesn't print anything, instead
arr = [2]
for r in arr:
print(r)
print("Why?")
prints:
2
why?
why? because, it has an element to go through
Please do not use list as a variable name.
You can simply do if item['institutions'] it will only proceed if the list is non-empty
lst = [{'author_position': 'first',
'author': {'id': 'https://openalex.org/A5012408034',
'display_name': 'Vincent S. Tagliabracci',
'orcid': 'https://orcid.org/0000-0002-9735-4678'},
'institutions': [],
'is_corresponding': False,
'raw_affiliation_string': 'Molecular Biology',
'raw_affiliation_strings': ['Molecular Biology']},
{'author_position': 'last',
'author': {'id': 'https://openalex.org/A5076217348',
'display_name': 'Peter J. Roach',
'orcid': None},
'institutions': [{'id': 'https://openalex.org/I55769427',
'display_name': 'Indiana University – Purdue University Indianapolis',
'ror': 'https://ror.org/05gxnyn08',
'country_code': 'US',
'type': 'education'}],
'is_corresponding': False,
'raw_affiliation_string': 'Indiana-University Purdue-University Indianapolis',
'raw_affiliation_strings': ['Indiana-University Purdue-University Indianapolis']}]
author_id = []
institution_id = []
for item in lst:
author_id.append(item['author']['id'])
if item['institutions']:
institution_id.append(item['institutions'][0]['id'])
In the list is empty you cannot access any index, since list[0] means that you access the first item in the list.
Instead, you should first check if the list contains any items like:
if len(list) > 0:
Your output=[] is inside your for loop. So at each iteration, its value is reinitialized, you should try again with output=[] before the for loop
Your output list is empty when you return it because every time the for loop restarts you reset the list.
Your code should look like this:
messages = {
"Placeholder": 0,
"1": 48,
"2": 4,
"3": 31,
"4": 2
}
def pls():
messages_sorted = sorted(messages, key=messages.get, reverse=True)
output = []
for i in range(10):
try:
currp = str(messages_sorted[i])
if currp == "Placeholder":
print("PLACEHOLDER DETECTED")
return output
currpp = messages[currp]
output.append(f"{currp} has {currpp} and is Place {i+1}")
print(output)
except IndexError:
print("Index error")
except:
print("some other error")
return output
output = pls()
output = str(output)
output = output.replace("['", "")
output = output.replace("']", "")
print(output)