473,387 Members | 1,742 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

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 2913
Paul Rubin <http://ph****@NOSPAM.invalid> 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, "maintainability" 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.invalid> wrote in message
news:7x************@ruckus.brouhaha.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
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
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,...
8
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...
17
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...
16
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...
3
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....
0
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...
1
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...
6
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...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
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...
0
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,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

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.