Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么tkinter模块在通过命令行运行时会引发属性错误,而在通过空闲运行时不会引发属性错误?_Python_Python 3.x_Import_Tkinter_Namespaces - Fatal编程技术网

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

Python 为什么tkinter模块在通过命令行运行时会引发属性错误,而在通过空闲运行时不会引发属性错误?,python,python-3.x,import,tkinter,namespaces,Python,Python 3.x,Import,Tkinter,Namespaces,与通过IDLE的运行模块f5命令运行代码相比,通过命令行运行代码时是否会出现错误? 最近我一直在努力提高代码的可读性和健壮性。因此,我一直试图从模块导入中删除所有的*行。我曾经使用tkinter import*中的,我的这行代码工作得非常好: self.path=filedialog.askdirectory() 但现在我已将从tkinter导入*更改为将tkinter作为tk导入,并相应地更改了代码: self.path=tk.filedialog.askdirectory() 名为GUI.p

与通过IDLE的
运行模块f5
命令运行代码相比,通过命令行运行代码时是否会出现错误?

最近我一直在努力提高代码的可读性和健壮性。因此,我一直试图从模块导入中删除所有的
*
行。我曾经使用tkinter import*中的
,我的这行代码工作得非常好:

self.path=filedialog.askdirectory()

但现在我已将
从tkinter导入*
更改为
将tkinter作为tk导入
,并相应地更改了代码:

self.path=tk.filedialog.askdirectory()

名为GUI.py的文件导入此文件时使用:
from lib.filesearch import*
(我提到的代码行位于filesearch文件中)

我通过空闲运行代码,一切正常。我的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'

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

实际上,模块没有属性
filedialog
,它是一个子模块,您应该在使用它之前将其作为
import tkinter.filedialog
导入。您可以在空闲状态下使用
tk.filedialog
,而无需显式导入
filedialog
,因为它已导入

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

上面的代码将在标准python解释器中引发一个
KeyError
,但它将在空闲时返回类似
的内容。

我想首先说:如果知道要使用子模块,请始终显式导入它们。这个答案的结尾有一个更具说服力的例子,说明这一点很重要

由于
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库。其中一名维护人员表示,这实际上是一个闲置的bug

在Python3.6.5中(可能更早,只检查了这个版本)这个特定的差异已经被修复了,所以除了我下面展示的2个模块之外,它不再发生在所有模块中

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

Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 03:03:55)
# standard interpreter 
>>> 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) 
# IDLE
>>> 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
是在您刚刚导入tkinter
时加载的,因此从我测试的版本开始,只有
urlib.parse
encodings.ascii
(和
idlelib
模块,但通常生产代码不使用该模块)


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

>>> import pandas
>>> import http
>>> http.client
<module 'http.client' from '.../http/client.py'>
这样,当使用它的代码加载
http.client
时,您可能会得到一个子模块,该子模块可以正常工作,可能是通过使用碰巧使用它的库,否则将失败


这让我回到了我的初始点-始终显式导入子模块。

尝试添加一个简单的调试
print(tk)
,以查看它实际导入的内容。最初会想到不同的python路径。@Ilja从空闲:
和从命令行:
您需要使用导入tkinter.filedialog导入子模块来加载它,您不在IDLE中的原因是IDLE已经导入了它,因为它正在Tkinter上运行。请查看在其
\uuuuu init\uuuuuuuuuupy
属性中定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,有些软件包,如
numpy
matplotlib
导入了大量子模块,这就是为什么它们要花这么长时间才能加载,而另一些软件包,如
tkinter
PIL
则只加载您明确要求它们加载的软件包。从某种意义上说,这是一个空闲的bug,其内部操作就是这样暴露出来的。我希望有一天通过重构几个模块来解决这个问题,这样tkinter在用户代码运行之前就不会被导入到用户进程中。
>>> import http
>>> http.client
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'http' has no attribute 'client'