I'm studying a demo script from the paramiko package (forward.py) to familiarize myself with SSH tunneling in Python. When I opened the demo script in my IDE, I noticed some unused import warnings:
import getpass
import os # <--- IDE warning: "'os' imported but unused"
import socket # <--- IDE warning: "'socket' imported but unused"
import select
import SocketServer
import sys
from optparse import OptionParser
And sure enough, neither module is explicitly referenced in the script. I'm a neat freak, so I want to delete this clutter - but I'm also inexperienced and can't tell for certain if they're extraneous.
The most straightforward thing for me to do would be to delete the imports and then try to run the script without them, but I don't know that I would be able to tell if something wasn't working correctly since I'm still trying to understand how the script works.
I found a conversation that made me think there might be a reason to import a module without using it. But in investigating further it seems to me that the example in that conversation has nothing to do with the functionality of the code, and the user is just trying to follow a stylistic convention.
How can an import be justified if there is never a reference to whatever was imported? I guess there might be code that runs on import, e.g.:
"""
silly.py: this is very silly
"""
class ManBearPig(Man, Bear, Pig):
def __init__(self, name):
self.name = name
@classmethod
def summon(cls):
"""summon Gary"""
global Gary
Gary = cls('Gary')
ManBearPig.summon()
That seems like a terrible idea, but I'm not confident enough in my python-fu to be sure. socket is already imported within SocketServer so what's the point of importing it here if you're not using it explicitly?
Yes, it is safe enough to remove imports that your code doesn't use in the current module, or that do not themselves have side effects.
Python imports modules once and stores them in sys.modules for future reference; subsequent imports will re-use the already imported module object. Modules that have side effects make use of that, but they still have to be imported that one time.
For 'regular' modules, all you have is an extra reference to the module object or to objects within that module. That takes a modicum of extra memory (apart from the module object itself), so the cost isn't that high.
But you then do have to track what modules you have used, and what global names therefore can be in use in your code that could lead to bugs.
It's possible to write code whose behaviour depends on whether the module has already been imported in this file, but that the IDE will not recognize uses the module:
if globals().get('socket'):
do_the_right_thing()
else:
do_something_subtly_different_that_is_hard_to_spot()
The import of socket in SocketServer has no effect on whether socket appears in the namespace of forward.
But if you assume that the script is reasonably "normal" then it's safe to believe your IDE as to whether the code uses the module or not. Or you can eventually confirm by examining its code whether the IDE's opinion is correct.
There also could in theory be some other script somewhere that does:
import forward
if hasattr(forward, 'socket'):
good()
else:
subtly_bad()
Again, this is kind of not normal, but if your script forward has for some reason chosen to document that it has an attribute called socket, then removing that attribute would break its published interface. And of course the IDE knows nothing about what interface users of forward might expect to see.
Beware that the first time you find yourself writing code like this, is the moment that you can no longer assume that your own code is "normal". So do try to avoid it :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With