为什么要导入*和ttk?

12

我的理解是,一个tkinter程序的标准设置通常是这样开始的:

from tkinter import *
from tkinter import ttk

我知道tkinter是一个包,但如果我已经使用*导入了所有东西,为什么我还需要导入ttk?如果我删除第二行并尝试引用ttk,为什么会出现错误?


根据我的发现,在PyDev for Eclipse中,只有一个“import tkinter.ttk”似乎是唯一不会产生警告的东西。 - Pat
4个回答

20
当你使用 from some_package import * 时,Python会导入该包选择要导出的任何内容。它选择导出的内容可能是存储在包文件夹中的子集。为什么?没有特别的原因,这只是包作者决定做事情的方式。
关于要导出的信息在包内的__init__.py文件中定义(在本例中是tkinter/init.py)。如果你查看那个文件,你会注意到它并没有导入ttk本身,因此ttk不会被导出,因此不能使用通配符导入导入。
同样,没有特别的原因,其他的tkinter和ttk作者选择这样做的原因也是如此。
要了解更多有关封装机制的信息,请参阅Python教程的封装部分(https://docs.python.org/3/tutorial/modules.html#packages)。

更好的导入tkinter的方法

你可能认为这是标准的,因为许多教程都是这样做的,但通常这是一个不好的实践。更好的方法,我认为,是给tkinter库一个明确的名称:
# python 3.x
import tkinter as tk
from tkinter import ttk 

# python 2.x
import Tkinter as tk
import ttk

这将使你的代码更易于阅读,因为你必须明确指出你正在使用哪个工具包:

b1 = tk.Button(...) # uses a standard tk button
b2 = ttk.Button(...) # uses a ttk button

我想不出任何其他好的理由来以其他方式进行操作。全局导入虽然可以在每次调用tkinter函数时节省几个字节,但会牺牲代码的清晰度。此外,它还会强化一种可能渗透到您使用其他库的不良实践。

在我看来,真正的权威是PEP8,它对此问题有以下建议:

应避免使用通配符导入(from import *),因为这会使命名空间中存在哪些名称变得不清楚,这使读者和许多自动化工具感到困惑。有一种可辩解的情况需要使用通配符导入,即将内部接口重新发布为公共API的一部分(例如,将一个接口的纯Python实现覆盖为一个可选加速器模块的定义,并且无法预先知道将覆盖哪些定义)。


1
@Aerovistae:也许吧。我很难为一个不好的实践给出一个好的解释。这是我非常反感的一件事情,因为有很多tkinter教程都犯了这个错误。<耸肩> - Bryan Oakley
我更想知道为什么我已经导入了*,为什么还要导入ttk。 - temporary_user_name
@BryanOakley 虽然您提出了一个有道理的观点(我同意通配符导入是个坏主意,tk 别名更加整洁),但这并没有回答 OP 的问题。 - jonrsharpe
@jonrsharpe:好的,我已经添加了几段直接回答所提出问题的内容。 - Bryan Oakley

5

抱歉,您能详细说明一下吗?我不太明白您所说的让 init 文件导入 ttk 是什么意思。 - temporary_user_name
@Aerovistae,你有没有阅读文档 - jonrsharpe
这比我预期的更有帮助。文档通常会漏掉一些关键信息,但这个不错。 - temporary_user_name

1
简述: from tkinter import *导入文件/包tkinter,但这并不意味着它会从文件/包tkinter.ttk中导入。

-1

这里其他两个答案没有提到的是,ttk没有被导入,因为它是tkinter模块中的一个子模块,实际上是一个独立的模块。

所以当你导入tkinter时,你会得到所有直接属于tkinter的部分。

但是ttk不直接属于tkinter,因此必须显式地导入。

然而,Bryan Oakley指出了一个很好的观点,即将一个模块中的所有内容导入本地命名空间(许多新手都这样做)可能会在以后使用更多模块时导致大问题。这是因为这些模块中的一些可能共享函数名称,即使这些函数本身可能完全不同。

对于大型模块来说,最好总是这样做:

import module as mod

或者

import module

然后将函数作为模块命名空间的一部分进行引用:

module.function()

这样做可以让你更好地控制自己的操作,并且在后面更清晰地知道该函数实际上属于哪个部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接