Reputation: 573
My project consists of a lot of imports which are placed at 'global' scope.
from google.appengine.ext import ndb
from handlers import SomeHandler
import logging
import datetime # will only use this module ONCE
I want to use the datetime
module just once inside a specific handler. Should I import datetime within the handler or should I leave it in global scope?
import datetime # Should we import here?
class BookHandler(webapp2.RequestHandler):
import datetime # Or, should we import here?
def get(self):
today = datetime.datetime.now()
It seems like importing locally shows clearer dependency relationships. Is there any performance issue or other drawbacks to consider?
Upvotes: 0
Views: 70
Reputation: 55963
Hiding imports like this is an optimisation; whenever considering whether to optimise, verify that the proposed optimisation is really going to be effective.
Let's consider the specific example of datetime
first. Here's a simple app:
import sys
import webapp2
class Handler(webapp2.RequestHandler):
def get(self):
if 'datetime' in sys.modules:
self.response.write('The datetime module is already loaded.\n')
else:
self.response.write('The datetime module is not already loaded\n.')
self.response.write('%d modules have been loaded\n' % len(sys.modules))
count = sum(1 for x in sys.modules.values() if '/lib64' in repr(x))
self.response.write('%d standard library modules have been loaded\n' % count)
gcount = sum(1 for x in sys.modules.values() if 'appengine' in repr(x))
self.response.write('%d appengine modules have been loaded\n' % gcount)
application = webapp2.WSGIApplication([('/', Handler)])
If we visit the '/' url we see this output:
The datetime module is already loaded.
706 modules have been loaded
95 standard library modules have been loaded
207 appengine modules have been loaded
Even in this minimal app, datetime
has already been imported by the SDK*. Once Python has imported a module, futher imports only cost a single dictionary lookup, so there is no benefit in hiding the import. Given that the SDK has already imported 95 standard library modules and 207 SDK modules it follows that there is unlikely to be much benefit in hiding imports of commonly used standard library or SDK modules.
This leaves the question of imports of application code. Handlers can be lazy-loaded by declaring them as strings in routes, so that they are not imported until the route is visited:
app = webapp2.Application([('/foo', 'handlers.FooHandler')])
This technique permits optimising startup time without hiding imports in classes or methods, should you find that it is necessary.
The cost of lazy-loading, as the other answers point out, can be unexpected runtime errors. Moreover, if you choose of hide imports it can also decrease code readability, potentially cause structural problems, for example masking circular dependencies, and sets a poor example for less experienced developers, who may assume that hiding imports is idiomatic rather than an optimisation.
So, when considering optimising in this way:
*Relying on the SDK's sys.modules
being similar to that of the cloud runtime is, I hope, a reasonable assumption.
Upvotes: 1
Reputation: 39809
There is no problem importing inside the handler (or even inside the get()
function if you prefer) - I'm using it massively.
Advantages of lazy-loading:
Disadvantages of lazy-loading:
Related (in the lazy-loading sense only): App Engine: Few big scripts or many small ones?
Upvotes: 1
Reputation: 2880
you should defiantly import modules at the beginning of your file which will bound it to the scope of that file. I think what you are doing is called 'lazy loading' the modules and it can causes bugs at runtime, if the module is not installed or imported correctly.
By the way, the way python works is that every time you import a module the interpreter looks if the module has already been imported. If it has been imported then it will set a reference to it. In another word, it doesn't create a new instance of it.
What i recommend is to create a file for your handler class and import datetime and anything else you want at the beginning of that file.
Upvotes: 1