一、引言
函數(shù)式編程是提高效率的好辦法,因為把一些需要重復(fù)執(zhí)行的代碼進行了封裝,以后可以重復(fù)調(diào)用。此外,函數(shù)式編程也有助于形成自頂向下的設(shè)計思維。打包成exe可執(zhí)行文件主要是使程序能夠在非python環(huán)境下也能得到執(zhí)行,便于程序的分享使用。
二、turtle庫:畫圖
turtle是python自帶的標準庫,不需要額外安裝,可直接import turtle使用。這里以turtle畫圖作例子,演示函數(shù)式編程與打包。
在畫圖之前,需要了解這個畫布呈現(xiàn)的方式。
畫布就是一個小窗口,在調(diào)用turtle的時候作為畫圖呈現(xiàn)的平臺。在畫圖中,無論是設(shè)置畫布的位置大小,還是畫圖中使用到的畫筆,都要使用像素作為單位。畫圖的第一步就是設(shè)置畫布的位置。如上圖,畫布這個小窗口的定位和大小主要利用了四個字參數(shù),startx、starty、width和height。后兩者就是畫布的寬度和長度,前兩者是畫布左上角頂點距離屏幕左邊和屏幕頂部的距離。
為了準確定位畫布,我們需要知道屏幕的width和height。值得注意的是,在程序中屏幕分辨率并不一定是屏幕設(shè)置中的參數(shù),顯示設(shè)置1920*1080的屏幕在這里并不一定就是這一分辨率。因此需要檢測。
這里需要調(diào)用win32api檢測,需要安裝pywin32包。(在cmd中執(zhí)行pip install pywin32)
然后輸入:
import win32api,win32con # 需要安裝pywin32包print('Width:',win32api.GetSystemMetrics(win32con.SM_CXSCREEN))print('Height:',win32api.GetSystemMetrics(win32con.SM_CYSCREEN))
(注:文中代碼界面均可左右移動)
在輸出界面可以看到當(dāng)前屏幕的分辨率:
因此,盡管是1920*1080的屏幕。但是在這里像素只有1280*720。
根據(jù)這一分辨率,就可以設(shè)置畫布了:
t.setup(0.5,0.5,320,180)# Display Size is 1280*720,So the canvas is 640*360t.bgcolor('black')# turtle.setup(width=0.5, height=0.5, startx=None, starty=None)# 參數(shù):width, height: 輸入寬和高為整數(shù)時, 表示像素; 為小數(shù)時, 表示占據(jù)電腦屏幕的比例# (startx, starty): 這一坐標表示矩形窗口左上角頂點的位置, 如果為空,則窗口位于屏幕中心。
這里將畫布設(shè)置成640*360,長度寬度各取屏幕一般,然后通過換算使得畫布顯示在屏幕正中央。畫布中,畫筆的默認初始狀態(tài)是這樣的:
畫筆朝向:右
畫筆位置:(0,0)
在畫布中,又有一套自己的坐標系,以中心為(0,0)點,右邊為正x軸,上方為正y軸。一切效果都是這個畫筆實現(xiàn)的,隨著畫筆的軌跡變動,相應(yīng)的圖畫也就產(chǎn)生了。
三、函數(shù)式編程: def
對于一些重復(fù)性的東西,完全可以用函數(shù)封裝起來,只需要輸入?yún)?shù),就可以返回對應(yīng)的結(jié)果,這樣就可以極大的提高開發(fā)效率。在Python中,一個個標準庫和第三方庫就是大型的函數(shù)集合。
比如我要讓畫筆畫出字母“C”,我可以用函數(shù)封裝起來,只要調(diào)用這個函數(shù),輸入?yún)?shù),就能讓畫筆畫出對應(yīng)的字母,在需要繪畫大量字母的時候就省去了每次都要重新編程的冗余工作。
編寫函數(shù)最重要的就是標準化,并且適應(yīng)性要強。在不同的場景中,我肯定需要不同大小的字母“C”,那么就要設(shè)定參數(shù)使得字母“C”可以根據(jù)輸入的參數(shù)變化大小。為了標準化,可以將字母C放置在一個矩形里面,類似于:
統(tǒng)一設(shè)定畫筆在左下角,朝向右邊,以此為起點進行繪制,繪制完畢后回到該點,朝向不變。C可以用半圓表示,為了控制其大小,可以將高度設(shè)定為參數(shù)x,一切距離用這個x表示,那么整個字母大小就可以等比例控制而不會變形。這里的思路為:
抬起畫筆(不留軌跡)——前進0.5x——放下畫筆(開始有軌跡)——在該點順時針畫半圓——抬起畫筆——順著軌跡回到0.5x點——返回原點——放下畫筆(使畫筆回到初始狀態(tài))
這樣一來,畫筆從開始到繪制結(jié)束,這個函數(shù)調(diào)用以后仍然保持了初始狀態(tài),可以很好的與下一步進行對接,提高效率。否則,下一個函數(shù)調(diào)用還要把畫筆調(diào)整到對應(yīng)位置,十分麻煩。
對于這個操作,可以命名為C_Image(x=80)。設(shè)定的x=80是一個默認參數(shù),如果不輸入數(shù)字,將會默認為矩形高度為80像素。也可以輸入其他數(shù)字從而改變字母C的大小。代碼如下:
import turtle as tdef C_Image(x=80):#python中用def定義函數(shù) 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()#放下畫筆
同理,可以設(shè)計N_Image(x=80)、I_Image(x=80)等等。
字母N:
import turtle as tdef 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 tdef 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()
至于一些稍復(fù)雜的圖形繪制,就純粹是數(shù)學(xué)問題了。無非是計算出各個“路線”的長度,讓畫筆按照相應(yīng)的路徑進行繪制。
四、調(diào)用函數(shù)繪圖:main()
封裝好函數(shù)以后,需要一個主程序進行調(diào)用,構(gòu)成最終繪圖。這里可以設(shè)計一個main()函數(shù)對各個函數(shù)進行調(diào)用,構(gòu)成最終圖像。
由于在字母和字母之間經(jīng)常需要不留軌跡地讓畫筆前進后退移動,這里就封裝了兩個函數(shù)right_move(x=40)和left_move(x=40),讓畫筆抬起——右移(左移)x距離——放下畫筆,便于主函數(shù)這里挪動畫筆位置。
import turtle as tdef left_move(x=40): t.up() t.bk(x) t.down()def right_move(x=40): t.up() t.fd(x) t.down()
主函數(shù)可以這樣設(shè)計:
import turtle as tdef 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可執(zhí)行文件
重頭戲來了。
這樣一個程序,在安裝python環(huán)境中執(zhí)行也不太容易,比如用pycharm運行還需要設(shè)置運行名稱,py文件地址,python解釋器指定等等。用cmd運行還得打開cmd命令,鍵入py文件地址等等,還要考慮python有沒有放到環(huán)境變量里面。
要是能夠打包成exe就好了,雙擊運行,只要是windows終端都可以。
pyinstaller包就提供了這么一種方法,可以把python程序打包成exe可執(zhí)行文件,極大方便了程序的跨平臺運行。
首先需要安裝pywin32和pyinstaller包。可以在cmd中用以下命令安裝:
pip install pywin32pip install pyinstaller
安裝好以后就可以用cmd鍵入命令打包文件。命令格式為:
pyinstaller -F D:\Desktop\xxxx.py
回車后,
在運行這條命令的路徑下面會生成兩個文件夾,一個build是工程文件,可以刪除,另一個dist文件夾下面就存放著需要的exe文件。也可以給程序添加圖標等等,百度pyinstaller參數(shù)設(shè)置即可。
需要注意的是,文件路徑要求比較高,路徑中最好不要出現(xiàn)空格或者中文字符等特殊字符,否則可能會報錯。
雙擊打開exe,會跳出cmd界面,會有一小會延遲,過一會就會開始自動執(zhí)行。
這樣以來,編寫的python文件就可以在沒有安裝python環(huán)境的計算機中運行了。當(dāng)然,需要注意的是這個打包程序應(yīng)該只適用于比較簡單的程序(比如這里的畫圖),如果涉及大量前端界面交互,或者需要調(diào)用較為復(fù)雜的接口等,可能無法實現(xiàn)一鍵打包。
上述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 timeimport turtle as timport 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)# 參數(shù):width, height: 輸入寬和高為整數(shù)時, 表示像素; 為小數(shù)時, 表示占據(jù)電腦屏幕的比例# (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()), '程序結(jié)束!')