Why import * and then ttk? - python-3.x

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.

Related

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

importing custom module , don't load other import from the module

I'm trying to build some custom Python modules.
Even though I was able to use all modules. When I try to import a module other modules are being imported.
For example:
mod1.py
import os
import sys
def f(x):
return (x**2)
main.py
import mod1
dir(mod1.os)
how can I avoid this behaviour? The user should not be able to access the other modules from mod1. In this example os and sys.
Should I put the import statements inside the function? Are there other ways to prevent such thing?
The behavior you are seeing is perfectly normal.
Python does not hide elements quite so strongly as some other languages.
We're all adults here, and are expected to behave responsibly, without strong enforcement from the language.
Should I put the import statements inside the function?
No, your code is just fine the way it is.
If you plan to write a bunch of python code, you should follow the usual conventions that everyone else does, as shown in your example code. In main.py, if you want to access an os function, you should certainly import it there, rather than borrowing a reference from mod1.os.

Why do i need to import messagebox in python?

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.

Why don't I need to import sys?

I have 2 python scripts, both utilizing sys.stdout, sys.exit(), etc. In one script, PyCharm highlights "import sys" as gray, (meaning it is never used), and if I remove the import statement, the program works just fine, including sys.stdout and sys.exit().
However, the second module does not highlight "import sys" as gray, and if I try to run it without that statement, I get an error on the first occurrence of sys.stdout:
NameError: name 'sys' is not defined
I have looked up the official documentation for sys, which says
"This module provides access to some variables used or maintained by the interpreter and to functions that interact strongly with the interpreter. It is always available."
Yet, most guides or instructions on how to use sys tell you to import.
So, do I have to import it or not? Why does one program need to, but not the other?
Possibly important differences between the two programs:
One program has a main function, and imports the other program. This is the one that does not need to import sys. Perhaps it inherently imports sys when it imports the other one as a module?
It seems that the first script does not just import the second script; it imports * from it, like this:
in module_1:
from module_2 import *
And in module_2:
import sys
This causes module_1 to import sys, indirectly. If I change
from module_2 import *
to
import module_2
then it no longer works.

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.

Resources