Python 使用PyInstaller检查问题;可以获取类的源,但不能获取函数
我在这里的第一篇帖子,请耐心等待 我正在使用PyInstaller捆绑tkinter应用程序,在使用Python 使用PyInstaller检查问题;可以获取类的源,但不能获取函数,python,pyinstaller,inspect,Python,Pyinstaller,Inspect,我在这里的第一篇帖子,请耐心等待 我正在使用PyInstaller捆绑tkinter应用程序,在使用inspect库时遇到了一个问题。基本上,我可以调用我编写的类的源代码,但不能调用函数。我制作了这个人为的案例来证明: 我的文件夹结构如下: experiment/ ---experiment.py ---init.py ---resources/ /---resources.py /---init.py ---loader/ /---loader.py /---i
inspect
库时遇到了一个问题。基本上,我可以调用我编写的类的源代码,但不能调用函数。我制作了这个人为的案例来证明:
我的文件夹结构如下:
experiment/
---experiment.py
---init.py
---resources/
/---resources.py
/---init.py
---loader/
/---loader.py
/---init.py
resources.py
定义一个函数一个类:
def foo(a):
print(str(a) + ' is what you entered.')
class Bar:
def __init__(self, b):
self.b = b
loader.py
导入该函数和该类,并定义一个函数来打印其源代码:
import inspect
from resources import resources
def testfunc():
source_Bar = inspect.getsource(resources.Bar)
print(source_Bar)
source_foo = inspect.getsource(resources.foo)
print(source_foo)
然后experience.py
从loader.py
加载打印函数并调用它:
from loader.loader import testfunc
testfunc()
我可以在Python控制台中运行experience.py
,并获得预期的输出(源代码为foo
和Bar
)
然后,我使用PyInstaller从experience.py
(仅添加PyInstaller的虚拟环境)创建一个可执行文件。spec
文件未被触及(我可以共享它),但我确实将loader
和resources
目录复制/粘贴到dist/experience
,以便可执行文件可以找到它们。如果从命令提示符下运行experience.exe
,则会得到以下输出:
C:\Users\earne\Desktop\experiment\dist\experiment>experiment.exe
class Bar:
def __init__(self, b):
self.b = b
Traceback (most recent call last):
File "experiment\experiment.py", line 3, in <module>
File "experiment\loader\loader.py", line 9, in testfunc
File "inspect.py", line 973, in getsource
File "inspect.py", line 955, in getsourcelines
File "inspect.py", line 786, in findsource
OSError: could not get source code
[14188] Failed to execute script experiment
- Windows 10 64位
- 大量切换导入方法(例如显式导入 函数名,使用导入*,仅导入模块,使用 模块(功能)
- 乱搞
文件,比如将我的模块添加到.spec
分析的
参数中。 正如htgoebel所评论的,我已经看到了,并且我已经尝试将我的模块添加到
,但是我不确定我是否做对了,而且这似乎不是根本问题,因为类a.pure
的代码可以从同一个文件中找到Bar
- 我使用了最新的PyInstaller版本(3.6)和
https://github.com/pyinstaller/pyinstaller/archive/develop.zip
总的来说,最奇怪的部分似乎是类源代码可以找到,但函数不能,当它们在同一个文件中时-但也许PyInstaller在某种程度上让它变得更复杂,我不明白?如果你有任何建议或想让我尝试其他东西,请告诉我。乐意提供我能提供的任何其他信息/测试。干杯 在做了更多的探索之后,我找到了一个解决方案——尽管感觉不太理想 在
loader
中,我添加了语句来打印foo
和Bar
的模块和文件(不需要“mymod
”):
再次创建程序时,experience.exe
的输出指向foo
和Bar
之间的差异。mymod.Bar
的打印语句为:
C:\Users\...\dist\experiment\resources\resources.pyc
<module 'resources.resources' from 'C:\\Users\...\dist\\experiment\\resources\\resources.pyc'>
class Bar:
def __init__(self, b):
self.b = b
因此,Python似乎可以识别它们来自同一个模块,但不是实际的文件;对于Bar
,有一个指向.pyc
文件的绝对路径,而对于foo
,只有指向.py
文件的相对路径
因此,我尝试更改导入/更明确,并开始使用importlib
:
from importlib import import_module
mymod = import_module('resources.resources')
此修复了experience.exe
,以提供正确的输出:
C:\Users\...\dist\experiment\resources\resources.py
<module 'resources.resources' from 'C:\\Users\...\dist\\experiment\\resources\\resources.py'>
class Bar:
def __init__(self, b):
self.b = b
C:\Users\...\experiment\resources\resources.py
<module 'resources.resources' from 'C:\\Users\...\dist\\experiment\\resources\\resources.py'>
def foo(a):
print(str(a) + ' is what you entered.')
这在应用程序中起作用-看起来过于冗长和混乱,但最终它不会明显影响应用程序的功能,无论是作为.exe
还是作为Python脚本
如果有人想大喊一声,我还是很想知道这里发生了什么。如果没有,希望这能帮助别人。
experiment\resources\resources.py
<module 'resources.resources' from 'C:\\Users\...\dist\\experiment\\resources\\resources.pyc'>
Traceback (most recent call last):
... #same error as before
from importlib import import_module
mymod = import_module('resources.resources')
C:\Users\...\dist\experiment\resources\resources.py
<module 'resources.resources' from 'C:\\Users\...\dist\\experiment\\resources\\resources.py'>
class Bar:
def __init__(self, b):
self.b = b
C:\Users\...\experiment\resources\resources.py
<module 'resources.resources' from 'C:\\Users\...\dist\\experiment\\resources\\resources.py'>
def foo(a):
print(str(a) + ' is what you entered.')
import importlib.util
homedir = os.path.dirname(os.path.dirname(__file__)
resources_dir = os.path.join(homedir, 'resources/resources.py')
spec = importlib.util.spec_from_file_location("resources.resources", resources_dir)
mymod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mymod)
#I do os stuff to get a relative path to resources from loader