python编程高阶|python文件打包成exe

python文件打包成exe可执行文件: 以game2048.py脚本为例,实现打包生成可执行文件。
本文介绍将python文件打包成exe可执行文件的方法。
关键库: 提示:pyinstaller安装,使用实践。
1、 安装pyinstaller
anaconda大环境下安装运行:conda install pyinstaller
没有conda就在命令行中运行:pip install pyinstaller
【python编程高阶|python文件打包成exe】2、 打包python文件实例
将编写的2048游戏程序脚本保存在game2048.py中;
把它打包成exe需要在同一文件夹中打开命令行并输入:
pyinstaller -F ./game2048.py
回车后运行,如果一切顺利,文件夹中会多出一个后缀为spec的文件,以及两个名为dist和build的文件夹。
打开dist,可以找到game2048.exe,这就是生成的可执行文件。
3、pyinstaller的其他的选项,参数:
-i: 后接图标文件名,表示用自定义图标生成exe程序
-w: 生成的exe程序不带窗口执行
如果想只运行tkinter 页面,去掉dos窗口需要在打包的时候 加上 -w 参数
eg. pyinstaller -F calc.py -w
注意:

  1. pyinstaller需安装在脚本所依赖环境env里,或者打包时保证你的脚本运行和所依赖的env一致。比如,用命令行打包有默认python环境,而调试代码用的是另一个环境。
  2. 生成的exe文件可复制到电脑上的任何地方单独使用。
实践: 游戏脚本game2048.py
注意:游戏界面引入了curses库,Windows下使用该库的注意事项和安装。
# !/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 2021/8/6 15:15 # @Author: Haiyan T # @Email: 893190391@qq.com # @File: game2048.py# Begin to show your code! import curses# 绘制在下的用户界面和漂亮的图形 from random import randrange, choice from collections import defaultdictletter_codes = [ord(ch) for ch in 'WASDRQwasdrq']# 上左下右,ord函数是把字符转换成对应的数字 actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']# 上,左,下,右,重启,退出 actions_dict = dict(zip(letter_codes, actions * 2))# 把字母与动作对应起来。 zip是把元组中的值对应起来。 # print(actions_dict)def get_user_action(keyboard): char = "N"# char的初始值为N while char not in actions_dict: char = keyboard.getch() return actions_dict[char]# 阻塞+循环,直到获得用户有效输入才返回对应行为# 行列转置 def transpose(field): return [list(row) for row in zip(*field)]# zip函数里边加*号,是把行变列,列变行。# 列表前后颠倒 def invert(field): return [row[::-1] for row in field]# 创建棋盘 class GameField(object): def __init__(self, height=4, width=4, win=2048): self.height = height# 高 self.width = width# 宽 self.win_value = https://www.it610.com/article/win# 过关分数 self.score = 0# 当前分数 self.highscore = 0# 最高分 self.reset()# 重置棋盘def reset(self):# 定义一个reset函数 if self.score> self.highscore:# 如果当前分数大于最高分,那么把当前分数赋值给最高分 self.highscore = self.score self.score = 0# 当前分数恢复到0分 self.field = [[0 for i in range(self.width)] for j in range(self.height)]# 横纵坐标恢复到(0,0) self.spawn()# 调用spawn这个函数 self.spawn()def move(self, direction):# 定义move函数 def move_row_left(row):# 向左移 def tighten(row):# squeese non-zero elements together 把零散的非零单元挤到一块 new_row = [i for i in row if i != 0]# 如果i不等于零,把他们赋值到new_row这个元组中 new_row += [0 for i in range(len(row) - len(new_row))]# 其余位置用0补充 return new_row# 返回这个元组def merge(row):# 定义merge函数,用来合并单元 pair = False# pair初始值为假 new_row = []# new_row初始值为空 for i in range(len(row)):# 让i在格子里循环 if pair:# 如果pair为真 new_row.append(2 * row[i])# 那么把把row【i】的值乘以2,追加到new_row后边 self.score += 2 * row[i]# 并且得分为row【i】的值乘以2 pair = False# pair重新赋值为假 else:# 如果pair为真 if i + 1 < len(row) and row[i] == row[i + 1]:# 如果i+1还没到边界,并且此时的row【i】=row【i+1】 pair = True# 那么pair为真 new_row.append(0)# new_row后追加零 else: new_row.append(row[i])# 否则追加row【i】 assert len(new_row) == len(row)# 提醒两者长度一致 return new_row return tighten(merge(tighten(row)))# 反复合并,知道不能合并为止moves = {} moves['Left'] = lambda field:\ [move_row_left(row) for row in field]# 做移动 moves['Right'] = lambda field:\ invert(moves['Left'](invert(field)))# invert是逆转 moves['Up']= lambda field:\ transpose(moves['Left'](transpose(field)))# transpose是转置 moves['Down']= lambda field:\ transpose(moves['Right'](transpose(field)))if direction in moves: if self.move_is_possible(direction):# 如果移动方向在四个方向上, self.field = moves[direction](self.field)# 那么调用moves函数 self.spawn()# 产生随机数 return True else: return Falsedef is_win(self): return any(any(i >= self.win_value for i in row) for row in self.field)def is_gameover(self): return not any(self.move_is_possible(move) for move in actions)def draw(self, screen): help_string1 = '(W)Up (S)Down (A)Left (D)Right' help_string2 = '(R)Restart (Q)Exit' gameover_string = 'GAME OVER' win_string = 'YOU WIN!' def cast(string): screen.addstr(string + '\n')def draw_hor_separator(): line = '+' + ('+------' * self.width + '+')[1:] separator = defaultdict(lambda: line) if not hasattr(draw_hor_separator, "counter"): draw_hor_separator.counter = 0 cast(separator[draw_hor_separator.counter]) draw_hor_separator.counter += 1def draw_row(row): cast(''.join('|{: ^5} '.format(num) if num > 0 else '|' for num in row) + '|')screen.clear() cast('SCORE: ' + str(self.score)) if 0 != self.highscore: cast('HGHSCORE: ' + str(self.highscore)) for row in self.field: draw_hor_separator() draw_row(row) draw_hor_separator() if self.is_win(): cast(win_string) else: if self.is_gameover(): cast(gameover_string) else: cast(help_string1) cast(help_string2)def spawn(self): new_element = 4 if randrange(100) > 89 else 2 (i, j) = choice([(i, j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0]) self.field[i][j] = new_elementdef move_is_possible(self, direction): def row_is_left_movable(row): def change(i): # true if there'll be change in i-th tile if row[i] == 0 and row[i + 1] != 0:# Move return True if row[i] != 0 and row[i + 1] == row[i]:# Merge return True return False return any(change(i) for i in range(len(row) - 1))check = {} check['Left']= lambda field:\ any(row_is_left_movable(row) for row in field)check['Right'] = lambda field:\ check['Left'](invert(field))check['Up']= lambda field:\ check['Left'](transpose(field))check['Down']= lambda field:\ check['Right'](transpose(field))if direction in check: return check[direction](self.field) else: return Falsedef main(stdscr): def init(): # 重置游戏棋盘 game_field.reset() return 'Game'def not_game(state): # 画出 GameOver 或者 Win 的界面 game_field.draw(stdscr) # 读取用户输入得到action,判断是重启游戏还是结束游戏 action = get_user_action(stdscr) responses = defaultdict(lambda: state)# 默认是当前状态,没有行为就会一直在当前界面循环 responses['Restart'], responses['Exit'] = 'Init', 'Exit'# 对应不同的行为转换到不同的状态 return responses[action]def game(): # 画出当前棋盘状态 game_field.draw(stdscr) # 读取用户输入得到action action = get_user_action(stdscr)if action == 'Restart': return 'Init' if action == 'Exit': return 'Exit' if game_field.move(action):# move successful if game_field.is_win(): return 'Win' if game_field.is_gameover(): return 'Gameover' return 'Game'state_actions = { 'Init': init, 'Win': lambda: not_game('Win'), 'Gameover': lambda: not_game('Gameover'), 'Game': game }curses.use_default_colors() game_field = GameField(win=2048)state = 'Init'# 状态机开始循环 while state != 'Exit': state = state_actions[state]()curses.wrapper(main)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223

anaconda prompt下运行打包:
(DeepLearningSlideCaptcha) C:\Users\Administrator>pyinstaller -F E:\structure_learning\0304t\2048\game2048.py
  1. (DeepLearningSlideCaptcha) 环境,可使用activate切换。
  2. pyinstaller -F E:\structure_learning\0304t\2048\game2048.py 命令。
  3. 结果
...... 7280 INFO: checking EXE 7281 INFO: Building EXE because EXE-00.toc is non existent 7281 INFO: Building EXE from EXE-00.toc 7281 INFO: Appending archive to EXE C:\Users\Administrator\dist\game2048.exe 7286 INFO: Building EXE from EXE-00.toc completed successfully. 123456

测试:
  1. 直接打包
生成的exe程序如下:
python编程高阶|python文件打包成exe
文章图片

双击运行
python编程高阶|python文件打包成exe
文章图片

\2. 带图标打包
pyinstaller -F -i 图标地址 脚本地址
回车,打包完成
pyinstaller -F -i E:\TanhaiyanLearn\structure_learning\0304t\2048\2048.icoE:\TanhaiyanLearn\structure_learning\0304t\2048\game2048.pyE:\TanhaiyanLearn\structure_learning\0304t\2048\2048.icoE:\TanhaiyanLearn\structure_learning\0304t\2048\game2048.py 1

python编程高阶|python文件打包成exe
文章图片

python编程高阶|python文件打包成exe
文章图片

python编程高阶|python文件打包成exe
文章图片

    推荐阅读