Why do i need to import messagebox in python? - python-3.x

When you have this code already:
from tkinter import *
Assuming that this code means that it imports everything from the tkinter module,
why doesn't it import tkinter messagebox. I'd have to use this seperate code for it to work:
from tkinter import messagebox

That's simply the way the package was designed to work. The author of tkinter decided that importing "*" wouldn't import messagebox, or some of the other packages (ttk is another example)
Generally speaking, you should never do import * anyway.

Related

Spyder reorders my import statements - breaks function

I am using Spyder as Editor/IDE.
I play with the options to include files/function/modules form other olders just to get a better understanding of how it works.
But Spyder rearranges my import statements in alphabetical order and thus breaks my functionality:
This is what I need:
import sys
sys.path.insert(1,'d:/pathtohelloworld/')
import helloworld
But when I do "Save File" in Spyder, it rearranges to
import helloworld
import sys
sys.path.insert(1,'d:/pathtohelloworld/')
and of course it will fail, since it cannot import "helloworld" before the path is defined via sys.path.insert.
This alphabetical order might be a good python style, but how can I fix this issue ?

Doubts on openpyxl, python3

He guys, I am just a beginner in Python3. I have a question :
import openpyxl
from openpyxl.style import *
As you can see that I am importing the openpyxl module, but why I need to import the second one in order to style fonts and cells an on.
openpyxl is a package. It contains modules, such as style. You should import the package anyway (all package or individual items). You can either:
import openpyxl
from openpyxl.style import *
then use style items like item1, item2
or
from openpyxl import style
then use style items like style.item1, style.item2
You don't have to - you can just as easily do:
import openpyxl
openpyxl.styles.fonts()
Or:
from openpyxl import style
style.fonts()
It comes down to personal preference. Using * imports is generally frowned upon because there's a risk of polluting the namespace, but if you know this isn't going to happen, and you want to keep your lines of code shorter, it's acceptable.
You are importing openpyxl, which includes everything in openpyxl including openpyxl.style and everything inside that. But say you would like to use X function of openpyxl.style, then you would have to write:
openpyxl.style.X()
If you write the second line you can simpy write:
X()
Basically the second line imports all the contents of the namespace openpyxl.style into your current namespace, removing the hassle of having to write openpyxl.style. everytime. Although it is generally a good practice to not merge namespaces like this, and not use
from _________ import *
Rather you can write
import openpyxl.style as op
and then use the X function as :
op.X()
You can also omit the line
import openpyxl
if you are not using anything else from openpyxl other than that included in openpyxl.style

Converting Python 2.7 to Python 3 with tkinter

I have a working application using Python 2.7 and Tkinter that uses these constructs:
from Tkinter import *
import Tkinter
import tkFileDialog
class Window(Frame):
#...
# other functional code
#...
def ChangeCWD(self): #CWD is current working directory
root = Tkinter.Tk()
root.withdraw()
directory = tkFileDialog.askdirectory( ... )
root = Tk()
root.mainloop()
It has labels, buttons, canvas, multiple frames and file dialogue boxes and it all works nicely.
I have begun updating the code to work on Python 3.5 and, so far all functions seem to work except for the file dialog. This is where I have got to so far:
from tkinter import *
import tkinter
import tkinter.filedialog
class Window(Frame):
#...
# other functional code
#...
def ChangeCWD(self): #CWD is current working directory
root = tkinter.Tk()
root.withdraw()
directory = filedialog.askdirectory( ... )
root = Tk()
root.mainloop()
However this code produces the error
"NameError: name 'filedialog' is not defined"
when the filedialog.askdirectory() statement is reached. Could anyone provide any help to understand what I should do to correct the situation please?
As an aside, please be gentle with me! I've always been rather mystified by the various ways of invoking import statements and how to use "tk." or "root." before some function calls. There are simply too many conflicting explanations out on the web that I can't get a clear picture.
You use import tkinter.filedialog, which imports tkinter.filedialog with the namespace tkinter.filedialog, then you try to use filedialog in your code.
Pick one of these two:
change your call to tkinter.filedialog.askdirectory( ... )
change your import to import filedialog from tkinter, which will import tkinter.filedialog with the namespace filedialog.
Note: from tkinter import * might seem like it should import filedialog, but that * does not import submodules unless the package has explicitly specified that they should.

python 3 tkinter Pycharm - error on messagebox

Im writing a GUI and I say:
from tkinter import *
Further in the program theres a function wich is:
def nameFunc():
messagebox.showinfo(........)
The problem is that by running the code in the latest Pycharm, it tells me that messagebox is not defined even if I already imported everything from tkinter, it only works if I explicitly say:
from tkinter import messagebox
This only occurs when I run the code on Pycharm, in the standard python IDLE its fine.
Why?
PyCharm is behaving exactly as it should, if you take a look at the documentation on packages:
what happens when the user writes from sound.effects import *? Ideally, one would hope that this somehow goes out to the filesystem, finds which submodules are present in the package, and imports them all. This could take a long time and importing sub-modules might have unwanted side-effects that should only happen when the sub-module is explicitly imported.
The only solution is for the package author to provide an explicit index of the package. The import statement uses the following convention: if a package’s __init__.py code defines a list named __all__, it is taken to be the list of module names that should be imported when from package import * is encountered.
tkinter does not define a __all__ to automatically import submodules and you should be glad it doesn't import them all automatically:
import tkinter.__main__
print("this will only print after you close the test window")
the program only continues to run after a window pops up with the current tcl/Tk version and some other content is closed, to import submodules of the package you must explicitly import them with:
from tkinter import messagebox
however as I describe in my other answer here, because of how IDLE is built it has already loaded some of the submodules when your code is being executed in the idle Shell.

Why import * and then ttk?

My understanding is that the standard set-up for a tkinter program starts off like this:
from tkinter import *
from tkinter import ttk
I understand that tkinter is a package, but if I've already imported all with the *, why do I still need to import ttk? Why do I get an error if I take out the second line and try to reference ttk?
When you do from some_package import *, python will import whatever that package chooses to export. What it chooses to export may be a subset of what is actually stored in the package folder. Why is that? There's no particular reason, it's just how the package author decided to do things.
This information about what to export is defined in the __init__.py file that is inside the package (in this case, tkinter/init.py). If you look at that file you'll notice that it doesn't import ttk itself, thus ttk won't be exported and therefore can't be imported with a wildcard import.
Again, there's no particular reason other than that's how the authors of tkinter and ttk chose to do things.
For more information on the mechanics of packaging, see the packaging portion of the python tutorial (https://docs.python.org/3/tutorial/modules.html#packages)
The better way to import tkinter
You may think it's standard because many tutorials do it that way, but it's generally a bad practice. The better way, IMO, is to give the tkinter library an explicit name:
# python 3.x
import tkinter as tk
from tkinter import ttk
# python 2.x
import Tkinter as tk
import ttk
This will make your code considerably easier to read, because you have to explicitly state which toolkit you are using:
b1 = tk.Button(...) # uses a standard tk button
b2 = ttk.Button(...) # uses a ttk button
I can think of no good reason to do it any other way. Doing a global import saves you a couple of bytes each time you call a tkinter function, but at the expense of clarity. Plus, it reinforces a bad practice that might bleed into how you use other libraries.
The real authority, IMO, is PEP8, which has this to say on the matter:
Wildcard imports (from import *) should be avoided as they make it unclear which names are present in the namespace, confusing both readers and many automated tools. There is one defensible use case for a wildcard import, which is to republish an internal interface as part of a public API (for example, overwriting a pure Python implementation of an interface with the definitions from an optional accelerator module and exactly which definitions will be overwritten isn't known in advance).
Because tkinter/__init__.py doesn't import ttk, so ttk isn't included in from tkinter import *.
Briefly: from tkinter import * imports from file/packet tkinter but it doesn't mean that it will import from file/packet tkinter.ttk
what the other two answers here failed to state is that ttk is not imported because it is a submodule within the tkinter module, effectively a module in itself.
so when you import tkinter you get all of the parts that directly belong to tkinter
but ttk does not directly belong and so must be imported explicitly.
however Bryan Oakley makes a good point that importing everything from a module into local namespace (as many newbies do) can lead to big problems later on when you start to use more modules. this is because some of these modules may share function names even though the functions themselves may do completely different things.
it is always best for large modules to do:
import module as mod
or
import module
and then reference the functions as belonging to the modules namespace:
module.function()
this gives you more control over what you are doing and makes it clearer later on what the function actually belonged to.

Resources