[Tutor] import * not allowed at function level - wassup?
Dave Angel
davea at davea.name
Thu Jun 6 12:22:38 CEST 2013
On 06/06/2013 05:30 AM, Jim Mooney wrote:
> In the program below, which now works, I tried to use "from
> tkinter.constants import *" to throw up an error message with tkinter,
> and got the error "import * only allowed at module level." So I
> instead imported tkinter.constants, but then I had to prepend every
> constant with tkinter.constants, which is annoying. Is there a way
> around that prohibition (and what's it for, anyway?)
from xx import *
is generally discouraged, for a reason known as "namespace pollution."
Once you've done that in a module, you no longer can tell from the
source file where a particular symbol comes from. Further, if you do it
from more than one module, then the latter module hides symbols from the
earlier one, invisibly. If the modules change over time, then features
you don't even use might stop features that you do from working properly.
Instead, try to use:
from xx import CONST1, CONST2, func3, func4, Class5
Here we can tell which constants, functions, and classes we're getting
from the module, and can readily tell if there are any conflicts.
Further, we can use the "as" notation to rename those that do create
conflicts.
As for using the first form inside a function, it's probably useful to
point out that locals inside functions are treated specially, and this
special treatment leads not only to smaller compiled code, but faster
(frequently much faster) code. The compiler decides what all the local
variables are for a given function, and gives each a number. The number
of slots is known when the function is entered, so a fixed structure can
be used. And each value is looked up at runtime by index (or slot
number), and not by name.
You may have already seen the other effect of this, which is that you
can't usefully add new entries to locals() inside a function.
So inside the function, use the same syntax shown above. I don't use
tkinter, so I may mess it up some. But something like:
def die_on_errors():
from tkinter.constants import BOTH, X
#now BOTH and X are directly accessible, as local (constant)
variables. Without qualifiers. Although X is a terrible name, perhaps
it has some useful mnemonic in tkinter-speak.
Another comment, since you're referring to constants. No reason that
the function cannot refer to global constants, since it won't be doing
any assignments to them, and therefore they don't need slots. However,
I hesitate to point that out, since it permits you to not only use the
dreaded 'from xx import *' but it also separates reference to these
arbitrary, undeclared names from their point of import.
>
> So I kludged the problem a bit by letting K = tkinter.constants, but
> I'd still just like to use the constants without any qualifiers, which
> I can do without a function. Except the error routine doesn't belong
> in the main program,
I hope you're not implying that you have a non-trivial "program" as
top-level code ?? !! Looking further, it appears you are. Please learn
to use
if __name__ == "__main__":
doit()
or equivalent. Doesn't matter for toy projects, but sooner or later
you're going to write some code you want to modify later, or reuse as a
module. At that point you'll wish it were already in functions.
Good rule of thumb is to include only the following kinds of things at
top-level:
1) imports
2) the above if name==main thingie
3) calls to argv parsing
4) some help, in case argv stuff isn't right
5) calls to main(), whatever it's named
> IMHO, since it fuddles the main logic of getting
> a Fibonacci sequence. I want it out of the way and callable.
>
> (The message box appeared behind my editor, and was not visible, which
> drove me nuts, but it works fine at the dos prompt ;')
>
> #Using Python 3.3.2 on Win 7 - standard project, standard test file
> """Print a user-chosen Fibonacci sequence"""
> x = 0
> fib = [0,1]
> attempts = 0
>
> def die_on_errors():
> """Throw up a message box and quit if too many bad entries are made"""
> import tkinter
> import tkinter.constants
> K = tkinter.constants
> tk = tkinter.Tk()
> frame = tkinter.Frame(tk, relief=K.GROOVE, borderwidth=5)
> frame.pack(fill=K.BOTH,expand=1)
> label = tkinter.Label(frame, text="\n Too many errors, quitting \n ")
> label.pack(fill=K.X, expand=1)
> tk.mainloop()
>
> user_prompt = "How long do you want your Fibonacci sequence?"
> user_error = "That's not an integer, please enter the desired integer length\
> of your Fibonacci series again."
>
> while True:
> try:
> fiblong = int(input(user_prompt))
> break
> except ValueError:
> attempts += 1
> if attempts > 6:
> die_on_errors()
> exit('bye, bye')
> user_prompt = user_error
>
> for cnt in range(0,fiblong - 2):
> fib.append(fib[x] + fib[x+1])
> x += 1
>
Why have 'x' here, when cnt is precisely the same thing, and is defined
right here in the loop?
> print(fib)
>
>
--
DaveA
More information about the Tutor
mailing list