为什么 Python 3 的 tkinter 导入语法在 Python 2 中有效,但在 pyinstaller 中不起作用?



TL;DR:标题的第一部分在接受的答案(我自己的)中简单地回答。 第二部分,关于pyinstaller,从未得到答复。

我不建议浪费时间阅读这个问题的其余部分和许多评论。


我通过Anaconda运行Python 2.7,据我所知,我没有安装Python 3。 我对导入tkinter感到困惑. 关于 Stack Overflow 的其他几个问题表明,根据您运行的是 Python 2 还是 Python 3,tkinter有单独的模块和略有不同的导入语法。 但是,Python 3 语法在 Python 2中对我有用(请参阅下面代码中的注释)。 什么给?

import sys
print sys.version
# prints: 2.7.12 |Continuum Analytics, Inc.| (default, Jun 29 2016, 11:07:13) [MSC v.1500 64 bit (AMD64)]
# I hear these should not work in Python 2.  
# In reality, they work fine if run normally via the Python 2 interpreter.
# However, they do NOT work when I use pyinstaller to make an executable.
from tkinter import *
from tkinter import ttk, messagebox
# These work fine in Python 2, as they should, even if compiled into an exe.
from Tkinter import *
import ttk
import tkMessageBox

编辑:

针对布莱恩·奥克利的评论,print sys.path的结果是:

['C:\Users\...\tkinter test program', 
'C:\Miniconda\python27.zip', 
'C:\Miniconda\DLLs', 
'C:\Miniconda\lib', 
'C:\Miniconda\lib\plat-win', 
'C:\Miniconda\lib\lib-tk', 
'C:\Miniconda', 
'C:\Miniconda\lib\site-packages', 
'C:\Miniconda\lib\site-packages\win32', 
'C:\Miniconda\lib\site-packages\win32\lib', 
'C:\Miniconda\lib\site-packages\Pythonwin', 
'C:\Miniconda\lib\site-packages\setuptools-23.0.0-py2.7.egg']

作为对太阳熊的回答的回应,以下是我电脑上发生的事情:

C:>python
Python 2.7.12 |Continuum Analytics, Inc.| (default, Jun 29 2016, 11:07:13) [MSC
v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
Anaconda is brought to you by Continuum Analytics.
Please check out: http://continuum.io/thanks and https://anaconda.org
>>> import tkinter
>>>

回应Łukasz Rogalski的评论:

>>> import Tkinter
>>> print Tkinter.__file__
C:Minicondaliblib-tkTkinter.pyc
>>> import tkinter
>>> print tkinter.__file__
C:Minicondalibsite-packagestkinter__init__.pyc
>>>

针对 Sun Bear 回答评论中的讨论,这是C:Minicondalibsite-packagestkinter__init__.pyc的内容,它解释了为什么即使我使用的是 Python 2,import tkinter也可以工作:

from __future__ import absolute_import
import sys
if sys.version_info[0] < 3:
from Tkinter import *
else:
raise ImportError('This package should not be accessible on Python 3. '
'Either you are trying to run from the python-future src folder '
'or your installation of python-future is corrupted.')

问题 1:为什么 Python 2 解释器可以执行此 Python 3 代码?

from tkinter import *
from tkinter import ttk, messagebox

答:(从我的问题更新和我/其他人的评论中合并)使它工作的是模块python-future。 安装该模块会创建各种"包装器"文件,这些文件除了将 Python 3 元素重定向到它们的 Python 2 对应项外,什么都不做:tkinter->Tkintertkinter.ttk->ttktkinter.messagebox->tkMessageBox等。 这是python-future模块的主要目的之一。

例如,这是C:Minicondalibsite-packagestkinter__init__.pyc

from __future__ import absolute_import
import sys
if sys.version_info[0] < 3:
from Tkinter import *
else:
raise ImportError('This package should not be accessible on Python 3. '
'Either you are trying to run from the python-future src folder '
'or your installation of python-future is corrupted.')

问题2:为什么相同的技巧似乎与模块pyinstaller不兼容?

答:我不知道。 这里没有人讨论过它,我不在乎 6 年后自己重新审视它。

tkinter是一个适用于Python 3语法的Python 3包装层Tk。
Tkinter是一个适用于 Python 2 语法的 Python 2 包装层 Tk。

导入命令是相同的。但是您需要为用于编写代码的 python 版本类型导入正确的包装器。下面显示python 2只能导入Tkinter而不能导入tkinter

$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named tkinter
>>> import Tkinter
>>> 

更新:如果Miniconda选择偏离主流做法并在幕后做一些事情来允许你所描述的事情,那么它是由Miniconda自行决定的。您的print tkinter.__file__命令显示您有tkinterprint Tkinter.__file__命令显示您有Tkinter。简而言之,Miniconda预装了Tkintertkinter。您是否尝试过比较这两个文件以查看它们是相同还是不同?

最新更新