Why PEP8 states imports should usually be on separate lines? - python

From PEP 8:
- Imports should usually be on separate lines, e.g.:
Yes: import os
import sys
No: import sys, os
it's okay to say this though:
from subprocess import Popen, PIPE
I thought comma separated style is simpler, shorter, easier to read and write, until I read PEP8. Does it have any disadvantage? PEP 8 didn't give any explaination about that.
So my question is, why is that bad?

One reason might be that it's easier for source control systems to identify differences on a per-line basis than it is to do that within source lines.
Like a lot of PEP 8, it's a matter of preference. Consistency is more important than which option you end up choosing.

Related

Python blank line convention among import statements

I was writing some code in Python when I suddenly became curious regarding blank line conventions for import statements.
I'm aware of the typical import statement conventions specified in the PEP 8 style guide and for blank lines as well. However, I became curious if there is a convention or unwritten rule for blank lines among import statements.
For example, I usually like to put a blank line in between the three categories that are specified in PEP 8 (i.e. standard library imports, related third party imports, local application/library specific imports) but I've also noticed that many people tend not to do so. My PyLint application even throws a warning whenever I put a blank line.
I personally felt that this added a bit of clarity as to what "category" each imported library falls into. Is there a sort of convention that I should be following?
Thanks in advance.
instead of blank line use a comment line in between the imports specifying what categories they fall into...
it brings more clarity and no warnings or errors will be raised
Yes. The convention is to separate the sections. http://github.com/timothycrosley/isort can help.
The sections might look like this.
from __future__ import absolute_import
import os
import sys
from third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8,
lib9, lib10, lib11, lib12, lib13, lib14, lib15)
from my_lib import Object, Object2, Object3
Alternatively, another popular, but not universal, convention is to only import modules, not classes or functions, as suggested in the Google Python Style Guide.
from __future__ import absolute_import
import os
import sys
import third_party.module1
import third_party.module2
import my_lib

Python: Importing multiple methods from external module

With very common Python modules, I find that importing using the from .. import statement greatly increases the readability of my code, since I can reference methods by name without the dot notation. However, in some modules, the methods I require are nested differently, e.g in os:
from os.path import join
from os import listdir, getcwd
Why doesn't from os import path.join, listdir, getcwd work? What would be a "pythonic" way to import all the methods I need in a more succinct manner?
The opinion on whether from <module> import <identifier> is Pythonic itself is quite split - it hides away the origin of a method so it's not easy to figure out whence a certain variable/function comes from just by perusing the code. On the other hand, it reduces verbosity which some people consider Pythonic even tho it's not specifically mandated. Either way, Pythonic is as elusive term as you're going to get and more often than not it means "the way I think Python code should look like" backed up by several PEPs and obscure mail list posts while conveniently omitting the ones that go against one's notion of Pythonic.
from os import path.join doesn't work because os defines the os.path module (by directly writing to sys.modules of all things), it's not an identifier in the os module itself. path, however, is an identifier in the os module pointing to the os.path module so you can do from os import path or from os.path import join.
Finally, succinct and Pythonic are not synonyms, in fact PEP 8 for example prescribes using multiple lines for multiple imports even tho you can succinctly write import <module1>, <module2>, <module3> .... It says that it's OK to import multiple identifiers like that, tho, but keep in mind that os and os.path are two different modules so based on PEP 8 they shouldn't be on the same line and therefore should be written as:
from os import <identifier_1>, <identifier_2>
from os.path import <identifier_3>, <identifier_4>
Now, I would go as far as claiming that this is Pythonic but it makes the most sense based on PEP 8, at least to me.

How to replace from x import * to import x in python code? [duplicate]

I was recently tasked with maintaining a bunch of code that uses from module import * fairly heavily.
This codebase has gotten big enough that import conflicts/naming ambiguity/"where the heck did this function come from, there are like eight imported modules that have one with the same name?!"ism have become more and more common.
Moving forward, I've been using explicit members (i.e. import module ... module.object.function() to make the maintenance work I do more readable.
But I was wondering: is there an IDE or utility which robustly parses Python code and refactors * import statements into module import statements, and then prepends the full module path onto all references to members of that module?
We're not using metaprogramming/reflection/inspect/monkeypatching heavily, so if aforementened IDE/util behaves poorly with such things, that is OK.
Not a perfect solution, but what I usually do is this:
Open Pydev
Remove all * imports
Use the optimize imports command (ctrl+shift+o) to re-add all the imports
Roughly solves the problem :)
If you want to build a solution yourself, try http://docs.python.org/library/modulefinder.html
Here are the other related tools mentioned:
working with AST directly, which is very low-level for your use.
working with modulefinder which may have a lot of the boilerplate code you are looking for,
rope, a refactoring library (#Lucas Graf),
the bicycle repair man, a refactoring libary
the logilab-astng library used in pylint
More about pylint
pylint is a very good tool built on top of ast that is already able to tell you where in your code there are from somemodule import * statements, as well as telling you which imports are not necessary.
example:
# next is what's on line 32
from re import *
this will complain:
W: 32,0: Wildcard import re
W: 32,0: Unused import finditer from wildcard import
W: 32,0: Unused import LOCALE from wildcard import
... # this is a long list ...
Towards a solution?
Note that in the above output pylint gives you the line numbers. it might be some effort, but a refactoring tool can look at those particular warnings, get the line number, import the module and look at the __all__ list, or using a sandboxed execfile() statement to see the module's global names (would modulefinder help with that? maybe...). With the list of global names from __all__ and the names that pylint complains about, you can have two set() and proceed to get the difference. Replace the line featuring wildcard imports with specific imports.
I wrote some refactoring tools to do just that. Star Namer will go through all of your wildcard * imports for a script and replace them with the actual functions to be imported.
Usage: ./star_namer.py module_filename script_filename
Once you've converted all of your star imports to actual names you can use from_to_import.py to fix them. This is how it works:
Running your script through pylint and counting up all of the currently undefined words.
Removing all of the from modname import lines from the script.
Running the script through pylint again and comparing the difference in undefined words.
Going through the json output of pylint (in reverse order), it determines the exact position of replacements to be made and inserts the modname. in the correct place.
I thought this approach would be a little more robust, by offloading the syntax processing to an advanced utility, that's designed for it, instead of trying to grep through all the text myself with regex expressions.
Usage: from_to_import.py script_name modname
It will show you what changes are to be made before making them. Press y to save. The main issues I've found so far are text alignment issues caused by inserting the modname. text which makes comments misaligned and it doesn't deal with aliased function names well (from ... import quickrun as qrun)
Full documentation here: https://github.com/SurpriseDog/Star-Wrangler

Is there anything bad about having multiple imports on one line?

When I'm programming in Python and I need to import multiple modules, I usually do I like this:
import random, time, matplotlib, cheese, doge
Then when I read over other people's code, this is what I see:
import random
import time
import matplotlib
import cheese
import doge
Why is this? Is there any difference between the two styles?
The practice of one import per line is standardized in PEP8, and following a common standard is reason enough to do as others do. Following a common standard follows the Principle of Least Astonishment, making it easier for people familiar with the standard to read and modify your code.
Even if you don't care about PEP8, though, one import per line makes your code more maintainable.
Imports are easier to skim/read:
It's easier to see that you are getting a fred in import fred than in import barney, betty, wilma, fred, bambam, pebbles
Imports are easier to locate:
Searching for "import fred" will find import fred and import fred, wilma, pebbles, but will not find import barney, fred
Imports are easier to edit:
Inserting and removing an entire line is fast in most editors.
There is only one module per line, so you don't have to search in the line to find the thing you wish to edit - it's at the end.
Relocating an import inside a module is just moving a whole line.
Copying one of several imports to another Python module is a copy-paste of a line,
rather than that copy-paste followed by trimming off the other imports you don't want.
Imports are easier to maintain:
Each changed module has its own line in the change-set - you don't have to read a line to figure out which module or modules changed.
Missing and added modules effect the line count on the file and in the change-set.
Typos are easier to pick out and correct on visual skim of the change-set.
One import per line would be a good idea even if it weren't the standard. Since it is the standard, it's doubly the best way to go.
As per PEP-8 (The Style Guide for Python Code)
Imports should usually be on separate lines, for e.g
Yes: import os
import sys
No: import sys, os
It's okay to say this though:
from subprocess import Popen, PIPE
To answer your question - both would work fine, but one is not conformant with the PEP8 guidelines.
I don't like to follow blindly without valid reason. As PEP20: Zen of Python states that "Readability Counts"
PEP8 "single line per import" works for general perspective. Although I respect his (i.e. Guido) opinion, I wouldn't always strictly follow this conventions all the time.
The exception for this rule is only when the # of code is smaller than the # of module import. e.g. 2 lines of code, but 4 module import.
This is more readable: (in my opinion)
import os, sys, math, time
def add_special():
return time.time() + math.floor(math.pow(sys.api_version + os.getpid(), 2))
instead of this
import os
import sys
import math
import time
def add_special():
return time.time() + math.floor(math.pow(sys.api_version + os.getpid(), 2))
But this readability matter differs for each individuals.
PEP-8, the official Python style guide, mandates that one package or module should be imported per line.
It is considered good style, and generally standardization makes programs easy to read. I don't think there are substantial differences under the hood to worry about, if that's what you're asking.
Those two examples are functionally equivalent. However, PEP 8, the official style-guide for Python, has a section here that condemns the practice of placing multiple imports on one line:
Imports should usually be on separate lines, e.g.:
Yes: import os
import sys
No: import sys, os
It's okay to say this though:
from subprocess import Popen, PIPE
Thus, many Python programmers place only one import per line in order to follow this guideline.

Is there an IDE/utility to refactor Python * imports to use standard module.member syntax?

I was recently tasked with maintaining a bunch of code that uses from module import * fairly heavily.
This codebase has gotten big enough that import conflicts/naming ambiguity/"where the heck did this function come from, there are like eight imported modules that have one with the same name?!"ism have become more and more common.
Moving forward, I've been using explicit members (i.e. import module ... module.object.function() to make the maintenance work I do more readable.
But I was wondering: is there an IDE or utility which robustly parses Python code and refactors * import statements into module import statements, and then prepends the full module path onto all references to members of that module?
We're not using metaprogramming/reflection/inspect/monkeypatching heavily, so if aforementened IDE/util behaves poorly with such things, that is OK.
Not a perfect solution, but what I usually do is this:
Open Pydev
Remove all * imports
Use the optimize imports command (ctrl+shift+o) to re-add all the imports
Roughly solves the problem :)
If you want to build a solution yourself, try http://docs.python.org/library/modulefinder.html
Here are the other related tools mentioned:
working with AST directly, which is very low-level for your use.
working with modulefinder which may have a lot of the boilerplate code you are looking for,
rope, a refactoring library (#Lucas Graf),
the bicycle repair man, a refactoring libary
the logilab-astng library used in pylint
More about pylint
pylint is a very good tool built on top of ast that is already able to tell you where in your code there are from somemodule import * statements, as well as telling you which imports are not necessary.
example:
# next is what's on line 32
from re import *
this will complain:
W: 32,0: Wildcard import re
W: 32,0: Unused import finditer from wildcard import
W: 32,0: Unused import LOCALE from wildcard import
... # this is a long list ...
Towards a solution?
Note that in the above output pylint gives you the line numbers. it might be some effort, but a refactoring tool can look at those particular warnings, get the line number, import the module and look at the __all__ list, or using a sandboxed execfile() statement to see the module's global names (would modulefinder help with that? maybe...). With the list of global names from __all__ and the names that pylint complains about, you can have two set() and proceed to get the difference. Replace the line featuring wildcard imports with specific imports.
I wrote some refactoring tools to do just that. Star Namer will go through all of your wildcard * imports for a script and replace them with the actual functions to be imported.
Usage: ./star_namer.py module_filename script_filename
Once you've converted all of your star imports to actual names you can use from_to_import.py to fix them. This is how it works:
Running your script through pylint and counting up all of the currently undefined words.
Removing all of the from modname import lines from the script.
Running the script through pylint again and comparing the difference in undefined words.
Going through the json output of pylint (in reverse order), it determines the exact position of replacements to be made and inserts the modname. in the correct place.
I thought this approach would be a little more robust, by offloading the syntax processing to an advanced utility, that's designed for it, instead of trying to grep through all the text myself with regex expressions.
Usage: from_to_import.py script_name modname
It will show you what changes are to be made before making them. Press y to save. The main issues I've found so far are text alignment issues caused by inserting the modname. text which makes comments misaligned and it doesn't deal with aliased function names well (from ... import quickrun as qrun)
Full documentation here: https://github.com/SurpriseDog/Star-Wrangler

Categories