What I Want to Do:
Check the different modules I've imported in my script (Python 2 or 3), and print their names. I'm currently using Python 2.7.12 and 3.6.4.
Where I Started:
The script simply imports modules, uses list comprehension to find what's there, and prints a list:
#!/usr/bin/env python
import sys
import os
import types
module_list = [i.__name__ for i in globals().values()
if type(i) == types.ModuleType and i in sys.modules.values()]
print(module_list)
I was initially running this in Python 3, and it works just fine (also fine for Python 2). The output is:
['__builtin__', 'sys', 'os', 'types'] # Python 2.
['builtins', 'sys', 'os', 'types'] # Python 3.
At this point, I decided to expand the list comprehension out, as I find it to be good practice in deciphering code/logical flow. So I replaced the single statement with:
module_list = []
for i in globals().values():
if type(i) == types.ModuleType and i in sys.modules.values():
module_list.append(i.__name__)
Here's where things get hairy. I get a RuntimeError
, and the output is now:
...
for i in globals().values():
RuntimeError: dictionary changed size during iteration
However, it still works in Python 2. I'm now more curious than anything else, and tried a few things.
What I Tried:
Turned
globals().values()
into a list:for i in list(globals().values()): if type(i) == types.ModuleType and i in sys.modules.values(): module_list.append(i.__name__)
This works as intended in Python 2 or 3.
Removed the
list()
and added in propermain
structure:def main(): module_list = [] for i in globals().values(): if type(i) == type(sys) and i in sys.modules.values(): module_list.append(i.__name__) print(module_list) if __name__ == '__main__': main()
This works as intended in Python 2 and 3.
To Recap:
- List comprehension works for Python 2 and 3.
- The
for
loop only works for Python 2. - Wrapping in a
list
works for Python 2 and 3. - Proper
main
structuring works for Python 2 and 3.
The Question:
What is it about that for
loop in Python 3 that's breaking things?