为什么tkinter模块在通过命令行运行时会引发属性错误,而在通过空闲运行时不会引发属性错误?

2024-09-27 07:24:29 发布

您现在位置:Python中文网/ 问答频道 /正文

与通过IDLE的run module f5命令运行代码相比,通过命令行运行代码是否会引发错误?

最近我一直在努力提高代码的可读性和健壮性。因此,我一直试图删除所有的from module import *行。我曾经使用from tkinter import *,我的这一行代码运行得非常好:

self.path = filedialog.askdirectory()

但现在我把from tkinter import *改成了import tkinter as tk,并相应地修改了代码:

self.path = tk.filedialog.askdirectory()

一个名为GUI.py的文件用from lib.filesearch import *(我提到的代码行位于filesearch文件中)导入这个文件

我通过IDLE运行代码,一切都很好。我的GUI仍然可以工作,而self.path = tk.filedialog.askdirectory()行的工作方式也很正常,但是,当我通过windows命令行运行代码时,会得到错误消息:

AttributeError: 'module' object has no attribute 'filedialog'

以下是我的代码中的相关部分:

来自filesearch.py

import tkinter as tk
    def get_path(self):
        """Store user chosen path to search"""
        self.paths = tk.filedialog.askdirectory(initialdir = FileSearch.DEFAULT)
        return self.paths

来自GUI.py

from lib.filesearch import *    
    def Browse(self):
        self.BrowseB['state']='disabled'
        self.p=self.CrawlObj.get_path()
        self.AddText('Searching from Path: ' + str(self.p))
        self.BrowseB['state']='normal'

与此不同,question我只安装了一个python版本。也就是说,Python34。


Tags: 文件path代码frompyimportselftkinter
2条回答

我想首先说:如果知道要使用子模块,请始终显式地导入它们。

由于tkinter的结构,您必须显式导入子模块才能加载:

import tkinter as tk
print(hasattr(tk,"filedialog")) # in a standard interpreter will print false
import tkinter.filedialog
print(hasattr(tk,"filedialog")) # should always print true after explicit import

不需要在IDLE中执行此操作的原因是,在代码运行之前,IDLE会在后台设置一些东西,并最终导入一些tkinter库。维护人员之一has commented认为这实际上是一个空闲的bug。

在python 3.6.5中(可能更早的版本,只检查了这个版本)这个特定的差异已经被修复了所以除了下面显示的2个模块之外,其他模块都不再发生这种情况。

在任何版本中,都可以看到加载了如下代码的子模块列表:

# standard interpreter
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 03:03:55) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> len(sys.modules) #total number of modules automatically loaded
71
>>> sorted(name for name in sys.modules.keys() if ("." in name)) #submodules loaded
['collections.abc', 'encodings.aliases', 'encodings.latin_1', 'encodings.utf_8', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib.abc', 'importlib.machinery', 'importlib.util', 'os.path']
>>> len(_) #number of submodules
10

空闲时:

Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 03:03:55) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "copyright", "credits" or "license()" for more information.
>>> import sys
>>> len(sys.modules)
152
>>> sorted(name for name in sys.modules.keys() if ("." in name and "idlelib" not in name))
['collections.abc', 'encodings.aliases', 'encodings.ascii', 'encodings.latin_1', 'encodings.utf_8', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib.abc', 'importlib.machinery', 'importlib.util', 'os.path', 'tkinter.constants', 'urllib.parse']
>>> len(_) #number of submodules not directly related to idlelib.
13

tkinter.constants是在您刚刚import tkinter时加载的,因此在我测试的版本中,这个问题仍然只存在于urllib.parseencodings.ascii(以及idlelib模块中,但通常生产代码不使用这个问题)


不过,这不一定是空闲的特定问题,更糟糕的问题是子模块是否由您使用的另一个库加载。以下面的代码为例:

>>> import pandas
>>> import http
>>> http.client
<module 'http.client' from '.../http/client.py'>

现在假设我们编写了一些其他代码,它们仍然使用http.client,但没有使用panda:

>>> import http
>>> http.client
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'http' has no attribute 'client'

这样,当使用它的代码加载http.client时,您就可以得到一个子模块,该子模块可以正常工作,这可能是由于使用了一个碰巧使用它但否则将失败的库。

这让我回到我的初始点-总是显式地导入子模块。

实际上,模块没有属性filedialog,它是一个子模块,在使用它之前应该将其导入为import tkinter.filedialog。您可以使用tk.filedialog而不显式地在IDLE中导入filedialog,因为它已经被导入。

import sys
sys.modules['tkinter.filedialog']

上面的代码将在标准python解释器中引发一个KeyError,但它将在IDLE中返回类似<module 'tkinter.filedialog' from '/usr/lib/python3.5/tkinter/filedialog.py'>的内容。

相关问题 更多 >

    热门问题