python文件打包成exe可执行文件:
以game2048.py脚本为例,实现打包生成可执行文件。
非计算机软件专业的我从大学开始学习计算机语言后,只知道如何写代码,运行调试,功能实现,总感觉差丢丢儿。后来因为兴趣和工作需要,每每写好一个算法或功能,我只能把源代码拿出去展示?莫名感觉没有档次,总感觉缺一丢丢。写了训练人工智能识别算法智能在cmd或IDE上面弄。换台电脑做算法就心累,环境布置,库安装要削减发量的有木有。所以,自己做不限制环境的工具非常有必要,而且发给朋友同事做数据处理超级适用。本文介绍将python文件打包成exe可执行文件的方法。
关键库:
提示:pyinstaller安装,使用实践。
1、 安装pyinstaller
anaconda大环境下安装运行:conda install pyinstaller
没有conda就在命令行中运行:pip install pyinstaller
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
注意:
pyinstaller需安装在脚本所依赖环境env里,或者打包时保证你的脚本运行和所依赖的env一致。比如,用命令行打包有默认python环境,而调试代码用的是另一个环境。
生成的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 randomimport randrange, choicefrom collectionsimport defaultdict
letter_codes=[ord(ch)for chin'WASDRQwasdrq']# 上左下右,ord函数是把字符转换成对应的数字
actions=['Up','Left','Down','Right','Restart','Exit']# 上,左,下,右,重启,退出
actions_dict=dict(zip(letter_codes, actions*2))# 把字母与动作对应起来。 zip是把元组中的值对应起来。# print(actions_dict)defget_user_action(keyboard):
char="N"# char的初始值为Nwhile charnotin actions_dict:
char= keyboard.getch()return actions_dict[char]# 阻塞+循环,直到获得用户有效输入才返回对应行为# 行列转置deftranspose(field):return[list(row)for rowinzip(*field)]# zip函数里边加*号,是把行变列,列变行。# 列表前后颠倒definvert(field):return[row[::-1]for rowin field]# 创建棋盘classGameField(object):def__init__(self, height=4, width=4, win=2048):
self.height= height# 高
self.width= width# 宽
self.win_value= win# 过关分数
self.score=0# 当前分数
self.highscore=0# 最高分
self.reset()# 重置棋盘defreset(self):# 定义一个reset函数if self.score> self.highscore:# 如果当前分数大于最高分,那么把当前分数赋值给最高分
self.highscore= self.score
self.score=0# 当前分数恢复到0分
self.field=[[0for iinrange(self.width)]for jinrange(self.height)]# 横纵坐标恢复到(0,0)
self.spawn()# 调用spawn这个函数
self.spawn()defmove(self, direction):# 定义move函数defmove_row_left(row):# 向左移deftighten(row):# squeese non-zero elements together 把零散的非零单元挤到一块
new_row=[ifor iin rowif i!=0]# 如果i不等于零,把他们赋值到new_row这个元组中
new_row+=[0for iinrange(len(row)-len(new_row))]# 其余位置用0补充return new_row# 返回这个元组defmerge(row):# 定义merge函数,用来合并单元
pair=False# pair初始值为假
new_row=[]# new_row初始值为空for iinrange(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】assertlen(new_row)==len(row)# 提醒两者长度一致return new_rowreturn tighten(merge(tighten(row)))# 反复合并,知道不能合并为止
moves={}
moves['Left']=lambda field: \[move_row_left(row)for rowin 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 directionin moves:if self.move_is_possible(direction):# 如果移动方向在四个方向上,
self.field= moves[direction](self.field)# 那么调用moves函数
self.spawn()# 产生随机数returnTrueelse:returnFalsedefis_win(self):returnany(any(i>= self.win_valuefor iin row)for rowin self.field)defis_gameover(self):returnnotany(self.move_is_possible(move)for movein actions)defdraw(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!'defcast(string):
screen.addstr(string+'\n')defdraw_hor_separator():
line='+'+('+------'* self.width+'+')[1:]
separator= defaultdict(lambda: line)ifnothasattr(draw_hor_separator,"counter"):
draw_hor_separator.counter=0
cast(separator[draw_hor_separator.counter])
draw_hor_separator.counter+=1defdraw_row(row):
cast(''.join('|{: ^5} '.format(num)if num>0else'| 'for numin row)+'|')
screen.clear()
cast('SCORE: '+str(self.score))if0!= self.highscore:
cast('HGHSCORE: '+str(self.highscore))for rowin 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)defspawn(self):
new_element=4if randrange(100)>89else2(i, j)= choice([(i, j)for iinrange(self.width)for jinrange(self.height)if self.field[i][j]==0])
self.field[i][j]= new_elementdefmove_is_possible(self, direction):defrow_is_left_movable(row):defchange(i):# true if there'll be change in i-th tileif row[i]==0and row[i+1]!=0:# MovereturnTrueif row[i]!=0and row[i+1]== row[i]:# MergereturnTruereturnFalsereturnany(change(i)for iinrange(len(row)-1))
check={}
check['Left']=lambda field: \any(row_is_left_movable(row)for rowin 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 directionin check:return check[direction](self.field)else:returnFalsedefmain(stdscr):definit():# 重置游戏棋盘
game_field.reset()return'Game'defnot_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]defgame():# 画出当前棋盘状态
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 successfulif 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)
anaconda prompt下运行打包:(DeepLearningSlideCaptcha) C:\Users\Administrator>pyinstaller -F E:\structure_learning\0304t\2048\game2048.py
- (DeepLearningSlideCaptcha) 环境,可使用
activate
切换。 - pyinstaller -F E:\structure_learning\0304t\2048\game2048.py 命令。
- 结果
......7280 INFO: checking EXE7281 INFO: Building EXE because EXE-00.tocis non existent7281 INFO: Building EXEfrom EXE-00.toc7281 INFO: Appending archive to EXE C:\Users\Administrator\dist\game2048.exe7286 INFO: Building EXEfrom EXE-00.toc completed successfully.
测试:
- 直接打包
生成的exe程序如下:
双击运行
2. 带图标打包
pyinstaller -F -i 图标地址 脚本地址
回车,打包完成
pyinstaller-F-i E:\TanhaiyanLearn\structure_learning\0304t\2048\2048.ico E:\TanhaiyanLearn\structure_learning\0304t\2048\game2048.pyE:\TanhaiyanLearn\structure_learning\0304t\2048\2048.ico E:\TanhaiyanLearn\structure_learning\0304t\2048\game2048.py