我想使用 pyinstaller 将 .py 文件制作成 exe 文件

I want to make .py file into exe file by using pyinstaller


我正在使用 pygame 制作程序,并希望将其制作成可执行文件。
如果它是 python 脚本,程序将 运行 正确。
但是有一个问题,如果我想把它做成可执行文件。
我制作了一个如下所示的规范文件,运行 它将所有依赖项捆绑到可执行文件中。
最后,我可以制作可执行文件,但它失败了 运行nning 并显示如下错误消息。

↓我收到错误消息(它说没有名为 "resources" 的文件夹!但我确实创建了虚拟文件夹。)
https://imgur.com/sq67mil

我该如何解决这个问题?

(我参考了这篇文档https://pyinstaller.readthedocs.io/en/v3.3.1/spec-files.html

PyInstaller 版本:3.3.1
Python版本:3.6.6

↓我的python脚本

#pygame_test.py located at Desktop/RPG_test
import pygame,sys,os
print(os.getcwd())
class Player(pygame.sprite.Sprite):
    def __init__(self,image_path,root):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(image_path).convert_alpha()
        self.rect = self.image.get_rect()

    def update(self):
        self.rect.centerx = pygame.mouse.get_pos()[0]
        self.rect.centery = pygame.mouse.get_pos()[1]

def main():
    pygame.init()
    root = pygame.display.set_mode((400,400))
    running = True
    player = Player("resources/tiger_window.png",root)
    group = pygame.sprite.Group()
    group.add(player)
    fps = 30
    clock = pygame.time.Clock()
    while running:
        clock.tick(fps)
        root.fill((50,150,200))
        group.update()
        group.draw(root)
        pygame.display.update()
        for event in pygame.event.get():
            if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
                running = False
                pygame.quit()
                sys.exit()
        pygame.event.clear()
if __name__ == "__main__":
    main()

↓我用"pyi-makespec"命令制作的spec文件。

# -*- mode: python -*-
block_cipher = None
a = Analysis(['pygame_test.py'],
         pathex=['C:\Users\Ayata\Desktop\RPG_test'],
         binaries=[],
         datas=[("C:/Users/Ayata/Desktop/RPG_test/resources/tiger_window.png","resources")],
         hiddenimports=[],
         hookspath=[],
         runtime_hooks=[],
         excludes=[],
         win_no_prefer_redirects=False,
         win_private_assemblies=False,
         cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
         cipher=block_cipher)
exe = EXE(pyz,
      a.scripts,
      a.binaries,
      a.zipfiles,
      a.datas,
      name='pygame_test',
      debug=False,
      strip=False,
      upx=True,
      runtime_tmpdir=None,
      console=True )

在你 运行 PyInstaller 构建的单文件可执行文件之后发生的第一件事就是 a temporary directory is created。然后可执行文件将一堆资源文件以及自定义数据文件(如您的 tiger_window.png 文件)解压缩到该目录中。在您的脚本中,您可以从变量 sys._MEIPASS.

检索到此目录的路径

以下代码片段应在 'development' 模式和 'frozen' 模式下提供图像文件的正确路径:

try:
    # Get temporary directory created by PyInstaller single-file executable
    base_path = sys._MEIPASS
except AttributeError:
    # Get directory in which this script file resides
    base_path = os.path.dirname(os.path.realpath(__file__))

# Get path to image file
img_path = os.path.join(base_path, 'resources/tiger_window.png')

备选方案

你也可以让 PyInstaller freeze your script into a directory (with multiple files) instead of just one single executable。如果您这样做,则无需修改您的脚本文件。一个额外的好处是您的游戏的启动时间可能会更短(因为不需要解压缩文件)。

@Bobsleigh 的回答很有帮助

你基本上需要将数据添加到 .spec 文件和 运行 "pyinstaller my_spec_file"(假设你想要一个目录包而不是一个文件 exe,两者之间的区别请访问 pyinstaller 文档)