PythonpythonPy

Python程序打包为exe可执行文件

2019-01-31  本文已影响415人  Maverick_7910

这是Python学习笔记系列的第五篇。

欢迎关注零壹研究 【微信号: Research_LAB】

全文约6000字,阅读约需9分钟


一、引言

函数式编程是提高效率的好办法,因为把一些需要重复执行的代码进行了封装,以后可以重复调用。此外,函数式编程也有助于形成自顶向下的设计思维。打包成exe可执行文件主要是使程序能够在非python环境下也能得到执行,便于程序的分享使用。

二、turtle库:画图

turtle是python自带的标准库,不需要额外安装,可直接import turtle使用。这里以turtle画图作例子,演示函数式编程与打包。

在画图之前,需要了解这个画布呈现的方式。

画布就是一个小窗口,在调用turtle的时候作为画图呈现的平台。在画图中,无论是设置画布的位置大小,还是画图中使用到的画笔,都要使用像素作为单位。画图的第一步就是设置画布的位置。如上图,画布这个小窗口的定位和大小主要利用了四个字参数,startx、starty、width和height。后两者就是画布的宽度和长度,前两者是画布左上角顶点距离屏幕左边和屏幕顶部的距离。

为了准确定位画布,我们需要知道屏幕的width和height。值得注意的是,在程序中屏幕分辨率并不一定是屏幕设置中的参数,显示设置1920*1080的屏幕在这里并不一定就是这一分辨率。因此需要检测。

这里需要调用win32api检测,需要安装pywin32包。(在cmd中执行pip install pywin32)

然后输入:

import win32api,win32con # 需要安装pywin32包

print("Width:",win32api.GetSystemMetrics(win32con.SM_CXSCREEN))
print("Height:",win32api.GetSystemMetrics(win32con.SM_CYSCREEN))

(注:文中代码界面均可左右移动)

在输出界面可以看到当前屏幕的分辨率:

因此,尽管是1920*1080的屏幕。但是在这里像素只有1280*720。

根据这一分辨率,就可以设置画布了:

t.setup(0.5,0.5,320,180)# Display Size is 1280*720,So the canvas is 640*360
t.bgcolor("black")
# turtle.setup(width=0.5, height=0.5, startx=None, starty=None)
# 参数:width, height: 输入宽和高为整数时, 表示像素; 为小数时, 表示占据电脑屏幕的比例
# (startx, starty): 这一坐标表示矩形窗口左上角顶点的位置, 如果为空,则窗口位于屏幕中心。

这里将画布设置成640*360,长度宽度各取屏幕一般,然后通过换算使得画布显示在屏幕正中央。画布中,画笔的默认初始状态是这样的:

画笔朝向:右

画笔位置:(0,0)

在画布中,又有一套自己的坐标系,以中心为(0,0)点,右边为正x轴,上方为正y轴。一切效果都是这个画笔实现的,随着画笔的轨迹变动,相应的图画也就产生了。

三、函数式编程: def

对于一些重复性的东西,完全可以用函数封装起来,只需要输入参数,就可以返回对应的结果,这样就可以极大的提高开发效率。在Python中,一个个标准库和第三方库就是大型的函数集合。

比如我要让画笔画出字母“C”,我可以用函数封装起来,只要调用这个函数,输入参数,就能让画笔画出对应的字母,在需要绘画大量字母的时候就省去了每次都要重新编程的冗余工作。

编写函数最重要的就是标准化,并且适应性要强。在不同的场景中,我肯定需要不同大小的字母“C”,那么就要设定参数使得字母“C”可以根据输入的参数变化大小。为了标准化,可以将字母C放置在一个矩形里面,类似于:

统一设定画笔在左下角,朝向右边,以此为起点进行绘制,绘制完毕后回到该点,朝向不变。C可以用半圆表示,为了控制其大小,可以将高度设定为参数x,一切距离用这个x表示,那么整个字母大小就可以等比例控制而不会变形。这里的思路为:

抬起画笔(不留轨迹)——前进0.5x——放下画笔(开始有轨迹)——在该点顺时针画半圆——抬起画笔——顺着轨迹回到0.5x点——返回原点——放下画笔(使画笔回到初始状态)

这样一来,画笔从开始到绘制结束,这个函数调用以后仍然保持了初始状态,可以很好的与下一步进行对接,提高效率。否则,下一个函数调用还要把画笔调整到对应位置,十分麻烦。

对于这个操作,可以命名为C_Image(x=80)。设定的x=80是一个默认参数,如果不输入数字,将会默认为矩形高度为80像素。也可以输入其他数字从而改变字母C的大小。代码如下:

import turtle as t

def C_Image(x=80):#python中用def定义函数
    t.up()#抬起画笔
    t.fd(0.5*x)#前进0.5x距离
    t.down()#放下画笔
    t.circle(0.5*x,-180)#逆时针画半圆
    t.up()#抬起画笔
    t.circle(0.5 * x, 180)#半圆原路返回
    t.bk(0.5*x)#后退0.5x
    t.down()#放下画笔

同理,可以设计N_Image(x=80)、I_Image(x=80)等等。

字母N:

import turtle as t

def N_Image(x=80):
    t.left(90)
    t.fd(x)
    t.right(180-26.565)
    t.fd(pow(1.25,0.5)*x)
    t.left(180-26.565)
    t.fd(x)
    t.up()
    t.left(90)
    t.fd(0.5*x)
    t.left(90)
    t.fd(x)
    t.left(90)
    t.down()

字母I:

import turtle as t

def I_image(x=80):
    t.fd(0.5*x)
    t.bk(0.25*x)
    t.left(90)
    t.fd(x)
    t.right(90)
    t.fd(0.25*x)
    t.bk(0.5*x)
    t.right(90)
    t.up()
    t.fd(x)
    t.left(90)
    t.down()

至于一些稍复杂的图形绘制,就纯粹是数学问题了。无非是计算出各个“路线”的长度,让画笔按照相应的路径进行绘制。

四、调用函数绘图:main()

封装好函数以后,需要一个主程序进行调用,构成最终绘图。这里可以设计一个main()函数对各个函数进行调用,构成最终图像。

由于在字母和字母之间经常需要不留轨迹地让画笔前进后退移动,这里就封装了两个函数right_move(x=40)和left_move(x=40),让画笔抬起——右移(左移)x距离——放下画笔,便于主函数这里挪动画笔位置。

import turtle as t

def left_move(x=40):
     t.up()
     t.bk(x)
     t.down()

def right_move(x=40):
     t.up()
     t.fd(x)
     t.down()

主函数可以这样设计:

import turtle as t

def main():
    # set canvas.
    t.setup(0.5, 0.5, 320, 180)  # Display Size is 1280*720,So the canvas is 640*360
    left_move(220)# move the pen.
    C_Image(x=80)
    right_move(100)
    N_Image(x=80)
    right_move(80)
    I_image()
    right_move(80)
    Love_Image()
    right_move(130)
    U_image()
    t.hideturtle()# hide the pen.
    t.up()
    t.setx(150)
    t.sety(-60)
    t.color("red")
    t.write("Jerry Mei, ECNU.", move=True, align="left", font=("Arial", 10, "normal"))# write my name.
    t.down()

运行效果:

五、打包为exe可执行文件

重头戏来了。

这样一个程序,在安装python环境中执行也不太容易,比如用pycharm运行还需要设置运行名称,py文件地址,python解释器指定等等。用cmd运行还得打开cmd命令,键入py文件地址等等,还要考虑python有没有放到环境变量里面。

要是能够打包成exe就好了,双击运行,只要是windows终端都可以。

 pyinstaller包就提供了这么一种方法,可以把python程序打包成exe可执行文件,极大方便了程序的跨平台运行。

首先需要安装pywin32和pyinstaller包。可以在cmd中用以下命令安装:

pip install pywin32
pip install pyinstaller

安装好以后就可以用cmd键入命令打包文件。命令格式为:

pyinstaller -F D:\Desktop\xxxx.py

回车后,

在运行这条命令的路径下面会生成两个文件夹,一个build是工程文件,可以删除,另一个dist文件夹下面就存放着需要的exe文件。也可以给程序添加图标等等,百度pyinstaller参数设置即可。

需要注意的是,文件路径要求比较高,路径中最好不要出现空格或者中文字符等特殊字符,否则可能会报错。

双击打开exe,会跳出cmd界面,会有一小会延迟,过一会就会开始自动执行。

这样以来,编写的python文件就可以在没有安装python环境的计算机中运行了。当然,需要注意的是这个打包程序应该只适用于比较简单的程序(比如这里的画图),如果涉及大量前端界面交互,或者需要调用较为复杂的接口等,可能无法实现一键打包。

上述python文件完整代码如下:

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
#-------------------------------
# Time   :2019/1/29  21:23
# Author :Jerry Mei, ECNU
# Email  :meicczj@163.com
# IDE    :PyCharm
#-------------------------------
import time
import turtle as t
import win32api,win32con # 需要安装pywin32包

print(time.strftime("%Y-%m-%d %H:%M:%S:", time.localtime()), "程序开始!")
StartTime = time.perf_counter()

print("Display Width:",win32api.GetSystemMetrics(win32con.SM_CXSCREEN))
print("Display Height:",win32api.GetSystemMetrics(win32con.SM_CYSCREEN))


# turtle.setup(width=0.5, height=0.5, startx=None, starty=None)
# 参数:width, height: 输入宽和高为整数时, 表示像素; 为小数时, 表示占据电脑屏幕的比例
# (startx, starty): 这一坐标表示矩形窗口左上角顶点的位置, 如果为空,则窗口位于屏幕中心。

def C_Image(x=80):
    t.up()
    t.fd(0.5*x)
    t.down()
    t.circle(0.5*x,-180)
    t.up()
    t.circle(0.5 * x, 180)
    t.bk(0.5*x)
    t.down()

def N_Image(x=80):
    t.left(90)
    t.fd(x)
    t.right(180-26.565)
    t.fd(pow(1.25,0.5)*x)
    t.left(180-26.565)
    t.fd(x)
    t.up()
    t.left(90)
    t.fd(0.5*x)
    t.left(90)
    t.fd(x)
    t.left(90)
    t.down()


def I_image(x=80):
    t.fd(0.5*x)
    t.bk(0.25*x)
    t.left(90)
    t.fd(x)
    t.right(90)
    t.fd(0.25*x)
    t.bk(0.5*x)
    t.right(90)
    t.up()
    t.fd(x)
    t.left(90)
    t.down()

def Love_Image(h=80):# height=(3*2^(0.5)+2)/4*x=80,x=4*h/(3*2^(0.5)+2)
    x = 4*h / (3 * pow(2,0.5) + 2)
    t.up()
    t.fd((0.5+0.25*pow(2,0.5))* x)
    t.down()
    t.color("red","pink")
    t.begin_fill()
    t.left(45)
    t.fd(x)
    t.circle(0.5*x,180)
    t.right(90)
    t.circle(0.5*x,180)
    t.fd(x)
    t.end_fill()
    t.left(45)
    t.up()
    t.bk((0.5+ 0.25 * pow(2,0.5)) * x)
    t.down()
    t.color("black")

def U_image(x=80):
    t.left(90)
    t.fd(x)
    t.right(90)
    t.up()
    t.fd(0.5*x)
    t.down()
    t.right(90)
    t.fd(x)
    t.left(90)
    t.bk(0.5*x)

def left_move(x=40):
     t.up()
     t.bk(x)
     t.down()

def right_move(x=40):
     t.up()
     t.fd(x)
     t.down()

def main():
    #set canvas.
    t.setup(0.5, 0.5, 320, 180)  # Display Size is 1280*720,So the canvas is 640*360
    left_move(220)#move the pen.
    C_Image(x=80)
    right_move(100)
    N_Image(x=80)
    right_move(80)
    I_image()
    right_move(80)
    Love_Image()
    right_move(130)
    U_image()
    t.hideturtle()# hide the pen.
    t.up()
    t.setx(150)
    t.sety(-60)
    t.color("red")
    t.write("Jerry Mei, ECNU.", move=True, align="left", font=("Arial", 10, "normal"))#write my name.
    t.down()

main()
# t.right(180)
# t.done() # 使得画面停留
time.sleep(5)#使画面停留5秒


EndTime = time.perf_counter()
print("程序总共用时:{:.2f}秒".format(EndTime - StartTime))
print(time.strftime("%Y-%m-%d %H:%M:%S:", time.localtime()), "程序结束!")

--End--

                                  好看!


上一篇下一篇

猜你喜欢

热点阅读