473,700 Members | 2,781 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Why import only at module level?

That's what the Python style guides advise. They don't seem to like

def frob(x):
import re
if re.search('sdf[234]xyz', x): ...

instead preferring that you pollute your module's global namespace
with the names of all your imports. What's the point of that? It
gets worse when you want to do something like

def dispatch(obj):
from types import *
if type(obj) == ListType: obj_list(obj)
elif type(obj) == FunctionType: obj_fcn(obj)
...

here you actually get a syntax warning that "from ... import *" is not
ALLOWED except at the module level. So the pollution is really
serious in that case, you're spewing all the names from the imported
module into your own module. And I know that "import *" is considered
uncool these days, but sometimes you really do want to just grab all
those symbols, and the whole point of wanting the import inside the
function is to contain the big import to a limited scope where they
won't conflict with your own symbols.

So what's the reason for the syntax warning, and for the convention of
putting the imports at the top of the module?
Jul 18 '05 #1
9 2934
Paul Rubin <http://ph****@NOSPAM.i nvalid> writes:
That's what the Python style guides advise. They ^^^^
I do wish people would stop using this word in this sort of context...
don't seem to like

def frob(x):
import re
if re.search('sdf[234]xyz', x): ...

instead preferring that you pollute your module's global namespace
with the names of all your imports. What's the point of that?
What's the problem with that?
It gets worse when you want to do something like

def dispatch(obj):
from types import *
if type(obj) == ListType: obj_list(obj)
elif type(obj) == FunctionType: obj_fcn(obj)
...

here you actually get a syntax warning that "from ... import *" is not
ALLOWED except at the module level.
The problem HERE is for nested scopes; it's impossible to know in

def f():
from baz import *
def g():
return y

where y is coming from (i.e. is it a captured binding or a global).
So what's the reason for the syntax warning, and for the convention of
putting the imports at the top of the module?


I think putting imports at the top is just so you can find them
easily, and at a glance see which modules a given module imports.

Cheers,
mwh

--
"The future" has arrived but they forgot to update the docs.
-- R. David Murray, 9 May 2000
Jul 18 '05 #2
Paul Rubin wrote:

That's what the Python style guides advise. They don't seem to like

def frob(x):
import re
if re.search('sdf[234]xyz', x): ...

instead preferring that you pollute your module's global namespace
with the names of all your imports. What's the point of that?


Maintainability . It's also well understood that there are potential
benefits to the approach you show above, late-loading of code being
one of them (which can improve startup time for certain apps), but
as maintainability should almost always be the primary consideration,
the standard advice is to put stuff together at the top where it's
clear to maintainers which modules are used in the code (in other
words, what a given module is coupled to).

-i've-been-playing-the-esp-game-so-i-channeled-the-style-guide-authors
-Peter
Jul 18 '05 #3
[Peter Hansen]
Paul Rubin wrote:
That's what the Python style guides advise. They don't seem to like def frob(x):
import re
if re.search('sdf[234]xyz', x): ... instead preferring that you pollute your module's global namespace
with the names of all your imports. What's the point of that?

Maintainability . It's also well understood that there are potential
benefits to the approach you show above, late-loading of code being
one of them (which can improve startup time for certain apps), but
as maintainability should almost always be the primary consideration,
the standard advice is to put stuff together at the top where it's
clear to maintainers which modules are used in the code (in other
words, what a given module is coupled to).


I never understood this "standard advice", nor how it is related to
maintainability . What makes a module significantly more maintainable
by merely grouping `import' statements at the beginning? What is it so
crucial to know that the `re' module is used, or not, in a program? It
looks like a tiny detail to me.

If for some strange reason I urgently needed to know everything that a
program imports, I guess I would then `grep' the source for the word
`import'i, or just search with an editor! :-) This is surely not a need
I often have, and for from enough for justifying the convention.

If within a `def', I will often use a module which I do not use
elsewhere in a program, there is no reason to make it global. Global
variables should be avoided on the average, and moreover, Python is
faster at accessing a local than a global.

I'm not really crusading for either method, but maybe a bit against
the mere existence of the "standard advice", unless it acquires some
better justification. Of course, "maintainabilit y" is a virtue, but the
relation between maintainability and the "standard advice" is asserted
as if it were to be evident, without explanation.

--
François Pinard http://www.iro.umontreal.ca/~pinard

Jul 18 '05 #4

"Paul Rubin" <http://ph****@NOSPAM.i nvalid> wrote in message
news:7x******** ****@ruckus.bro uhaha.com...
That's what the Python style guides advise. They don't seem to like

def frob(x):
import re
if re.search('sdf[234]xyz', x): ...

instead preferring that you pollute your module's global namespace
with the names of all your imports. What's the point of that? It
gets worse when you want to do something like

def dispatch(obj):
from types import *
if type(obj) == ListType: obj_list(obj)
elif type(obj) == FunctionType: obj_fcn(obj)
...

here you actually get a syntax warning that "from ... import *" is not
ALLOWED except at the module level. So the pollution is really
serious in that case, you're spewing all the names from the imported
module into your own module. And I know that "import *" is considered
uncool these days, but sometimes you really do want to just grab all
those symbols, and the whole point of wanting the import inside the
function is to contain the big import to a limited scope where they
won't conflict with your own symbols.

So what's the reason for the syntax warning, and for the convention of
putting the imports at the top of the module?


The reason to put imports at the top of the module
is that, in general, imported modules are global resources. That's
also why it's not an issue to insert them in the module level
namespace.

Also, there are certain very common program tasks, such
as creating a subclass, where the superclass has to be
available at module load time. If it's in another module, that
module has to be imported before defining the class.

That said, if a module isn't a global resource then there's
no particular reason to put the symbol in the module
symbol table. I use __import__ in my version of FIT
to import fixtures into a dictionary, for example. I prefer
that technique to attempting to exec a constructed
import statement precisely because I don't have any
control over the names of the imported modules.

From foobar import * is a specialized case that
should be used only when you know what the module
is going to import. If you don't want the scatter shot
loading, then just import foobar, and reference foobar.whatever
whenever you need a symbol. No one is holding an
assault weapon to your head to make you use import *
after all.

If you're a control freak (or your program analysis tools
barf on import *), you can always put assignments
for the symbols you're going to use after the imports.
That makes it explicit.

John Roth

Jul 18 '05 #5
François Pinard wrote:

[Peter Hansen]
Maintainability . It's also well understood that there are potential
benefits to the approach you show above, late-loading of code being
one of them (which can improve startup time for certain apps), but
as maintainability should almost always be the primary consideration,
the standard advice is to put stuff together at the top where it's
clear to maintainers which modules are used in the code (in other
words, what a given module is coupled to).
I never understood this "standard advice", nor how it is related to
maintainability . What makes a module significantly more maintainable
by merely grouping `import' statements at the beginning? What is it so
crucial to know that the `re' module is used, or not, in a program? It
looks like a tiny detail to me.


"re" is not a good example of the above, though there might also be
very good but different reasons to import re at the top. Often it
is used in several different places, and that would mean duplication
(and a tiny waste of time) if you always imported it at the beginning
of each method, or even just before it was used.

A better example is application-specific modules. "Hiding" those down
in the individual methods that use them makes it much more difficult
to see the coupling between modules.

More coupling means less maintainability .

Second reason: if you put your import, which you use in only one place,
locally in the method where it's used, then modify the code so that
another method also uses the module, you will end up with two imports.

More duplication means less maintainability .
If within a `def', I will often use a module which I do not use
elsewhere in a program, there is no reason to make it global. Global
variables should be avoided on the average, and moreover, Python is
faster at accessing a local than a global.


As you probably know, I almost never put performance anywhere near the
level I put other considerations, so if we still differ on this matter,
perhaps it's because of different values.

-Peter
Jul 18 '05 #6
[Peter Hansen]
François Pinard wrote: A better example is application-specific modules. "Hiding" those down
in the individual methods that use them makes it much more difficult
to see the coupling between modules.
Agreed indeed, the coupling between modules is less explicit then.
More coupling means less maintainability .
On the other hand, the location of `import' has no effect on the amount
of coupling.
Second reason: if you put your import, which you use in only one
place, locally in the method where it's used, then modify the code so
that another method also uses the module, you will end up with two
imports. More duplication means less maintainability .
Maybe not. I may have many functions each having a local counter, and
despite all the duplication, using a single global counter instead would
not imply more maintainability . Locality (of definition and use) is
often best for maintainability , even if it means random duplication.

There is no definitive rule about what is good or bad, and this is where
good taste comes in, which turns all this program writing into an art!
Global variables should be avoided on the average, and moreover,
Python is faster at accessing a local than a global.

As you probably know, I almost never put performance anywhere near the
level I put other considerations, so if we still differ on this matter,
perhaps it's because of different values.


Performance is not to be a primary concern on the average, quite
agreed! Still, a few simple habits are easily acquired that yield
faster programs on average, which happily coincide with good programming
practices. I consider this coincidence as a reason to rejoice! :-)

--
François Pinard http://www.iro.umontreal.ca/~pinard

Jul 18 '05 #7
François Pinard wrote:

[Peter Hansen]
More coupling means less maintainability .
On the other hand, the location of `import' has no effect on the amount
of coupling.


I think I can make a good argument that it does. Try this on for size:
if the import of module B is in several methods of module A, then each of
those methods is directly coupled to module B. You've got several
instances of coupling. Now move the duplicate imports up to the top
of module A. Each method is now coupled only to module A, which of
course all methods in that module are, but only module A has any
coupling to module B.

When I analyze coupling, I consider the links to have both strength
and quantity. Generally a reduction in quantity is just as useful
as a reduction in strength of coupling, IME.
Second reason: if you put your import, which you use in only one
place, locally in the method where it's used, then modify the code so
that another method also uses the module, you will end up with two
imports. More duplication means less maintainability .


Maybe not. I may have many functions each having a local counter, and
despite all the duplication, using a single global counter instead would
not imply more maintainability . Locality (of definition and use) is
often best for maintainability , even if it means random duplication.


Unfortunately you lost me with the example. I can't see the connection
between having separate local counters and a single global counter,
since presumably the logic requires either one or the other. (I trust
you had a valid point but I missed it, sorry.)
There is no definitive rule about what is good or bad, and this is where
good taste comes in, which turns all this program writing into an art!


Very true of course, as with all design.

-Peter
Jul 18 '05 #8
[Peter Hansen]
When I analyze coupling, I consider the links to have both strength
and quantity. Generally a reduction in quantity is just as useful
as a reduction in strength of coupling, IME.
This sounds all quite reasonable! :-)
Unfortunately you lost me with the example. [...] (I trust you had a
valid point but I missed it, sorry.)


Thanks for the confidence! :-) Let me not insist with the example, as
I'm not trying to make a point here :-). As long as we agree to seek for
aesthetic programs, the methods and tastes of the various artists may
differ, and the diversity is one more source of interest. Keep happy!

--
François Pinard http://www.iro.umontreal.ca/~pinard

Jul 18 '05 #9
Michael Hudson wrote:
def frob(x):
import re
if re.search('sdf[234]xyz', x): ...

instead preferring that you pollute your module's global namespace
with the names of all your imports. What's the point of that?
What's the problem with that?


(1) It breaks code encapsulation. Well, perhaps
"breaks" is too strong a word, but it makes data hiding
more difficult. Unless you jump through hoops to remove
all traces of the objects you import, modules that you
import will be visible to those that import you.

(2) It is messy. The whole point of nested scopes is to
make objects visible only to the objects that need
them. If only one function needs the import, why force
it to be visible to all the others?

(3) There was clearly a need (or at least a wish) to be
able to hide imported objects from importing modules.
The usual way of doing this is:

from spam import public as _notpublic

Making the import local to the calling function works
well too.

I sometimes delete the binding when I'm done:

from spam import public
# use public in here
del public

although there are disadvantages to this method.

[snip] The problem HERE is for nested scopes; it's
impossible to know in

def f():
from baz import *
def g():
return y

where y is coming from (i.e. is it a captured

binding > or a global).

Why is this any different from the following top-level
code:

# module baz:
y = "spam spam spam"
y= "I don't like spam"
from baz import *


Where is the binding y coming from? The question of
whether this code is at the top-level or in a function
definition is a red herring.
It seems to me that forbidding imports except at the
top level is an arbitrary restriction. Using import
insided function definitions might not work for some
people, but it works for others.

--
Steven D'Aprano
Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
6907
by: Stian Søiland | last post by:
all examples performed with: Python 2.3+ (#2, Aug 10 2003, 11:09:33) on linux2 (2, 3, 0, 'final', 1) This is a recursive import:
16
2746
by: Manlio Perillo | last post by:
Hi. I'm a new user of Python but I have noted a little problem. Python is a very good language but it is evolving, in particular its library is evolving. This can be a problem when, ad example, a module change its interface or its implementation in a fundamental way (an example: wxPython). This, I think, can be resolved by allowing an user to explicitly say what version of a module it wants (sush as version numbers in Linux shared...
8
2079
by: Grant D. Watson | last post by:
If this has been answered before, or if my terminology is off, please bear with me; my Python experience is limited to use in one class and to personal projects. I'd like to do something rather silly: I'd like to run a particular piece of code from a given module every time that the module is imported, and not just at the time that the module is originally loaded. So, every time a module says import foo or something analogous, I want...
17
1879
by: Jacek Generowicz | last post by:
I have a module whose behaviour needs to be configurable. The module needs to decide, the first time it is imported, beteween alternative interfaces it presents. Currently, I set some environment variables which select the desired behaviour, and the module inspects those variables to determine the mode in which it should set itself up. I would prefer a pure Python solution, rather than one which depends on external state. Can you...
16
3106
by: didier.doussaud | last post by:
I have a stange side effect in my project : in my project I need to write "gobal" to use global symbol : .... import math .... def f() : global math # necessary ?????? else next line generate an error message ?????
3
5422
by: Mudcat | last post by:
I have a directory structure that contains different modules that run depending on what the user selects. They are identical in name and structure, but what varies is the content of the functions. They will only need to be run once per execution. Example (directory level): Sys1: A B C
0
1458
by: Anders J. Munch | last post by:
Now 2.5 is out, and we have a syntax for explicit relative imports (PEP 328, http://www.python.org/dev/peps/pep-0328/, in case anyone wasn't paying attention). The long-term plan is that the classical import syntax becomes absolute import only, so that all imports are explicitly one or the other. You can only use relative import from within packages. Trying to import a top-level module relatively from within same directory, produces...
1
2349
by: lemke_juergen | last post by:
Hi everyone, I define some vars and functions in a "support" module which gets called from my main app module. Using Python 2.5. I import all symbols in the support module at the top of the main module through: from support import *
6
2359
by: robert | last post by:
I get python crashes and (in better cases) strange Python exceptions when (in most cases) importing and using cookielib lazy on demand in a thread. It is mainly with cookielib, but remember the problem also with other imports (e.g. urllib2 etc.). And again very often in all these cases where I get weired Python exceptions, the problem is around re-functions - usually during re.compile calls during import (see some of the exceptions below). But...
0
8641
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9203
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
8958
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
7797
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6557
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4396
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4650
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3082
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2021
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.