99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁精彩閱讀Pyinstaller打包,徹底解決圖片、數(shù)據(jù)路徑問題
Pyinstaller打包,徹底解決圖片、數(shù)據(jù)路徑問題
2022-03-04
收藏

作者:麥?zhǔn)?/span>

來源:麥?zhǔn)寰幊?/span>

Pyinstaller打包,解決圖片、數(shù)據(jù)路徑問題!

這是文件路徑系列的第5篇。很多網(wǎng)友碰到找不到文件的問題,都是因為對Python讀取文件路徑的知識理解不深。本周的每天3分鐘,我們就主要圍繞路徑問題。

如果要把Python打包成一個可執(zhí)行文件,或者一個文件夾,最常用的方式是pyinstaller。

使用方法很簡單,但是很多麥友會碰到路徑問題:如果代碼中需要用到圖片或數(shù)據(jù)文件,打包后執(zhí)行會失??!

咱們今天就來解決這個問題。篇幅有限,我演示一個簡單的例子,并指出解決更復(fù)雜的問題的方向。

案例介紹

本例子將要打包如下文件結(jié)構(gòu):

--058 --058.py --058.txt 

文件夾058下有兩個文件:058.py和058.txt。其中058.py源代碼如下:

import pathlib
folder = pathlib.Path(__file__).parent.resolve()
print(f'當(dāng)前python文件所在目錄:{folder}') with open(f'{folder}/058.txt') as file:
 print(file.read())

也就是說058.py文件需要用到058.txt文件。

直接運行,會打印出數(shù)據(jù)文件的內(nèi)容:

當(dāng)前python文件所在目錄:/Users/maishu/git/wx_maishucode/code/058
跟麥?zhǔn)甯愣窂絾栴}

我們的任務(wù)是:打包成一個exe文件,可以分發(fā)給沒有Python,不懂Python的人使用。

以下例子用Mac做演示,在Windows或Linux下也是一樣的。

安裝pyinstaller

pyinstaller是一個Python的模塊,我們先來安裝它。

在命令行下運行:

python -m pip install pyinstaller

執(zhí)行結(jié)果如下,安裝成功:

maishu@msmacbook 058 % python -m pip install pyinstaller
Collecting pyinstaller
  Downloading pyinstaller-4.9-py3-none-macosx_10_13_universal2.whl (1.6 MB)
     |████████████████████████████████| 1.6 MB 152 kB/s 
Collecting pyinstaller-hooks-contrib>=2020.6 Downloading pyinstaller_hooks_contrib-2022.2-py2.py3-none-any.whl (223 kB)
     |████████████████████████████████| 223 kB 117 kB/s 
Collecting macholib>=1.8 Downloading macholib-1.15.2-py2.py3-none-any.whl (37 kB)
Requirement already satisfied: setuptools in /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages (from pyinstaller) (57.4.0)
Collecting altgraph
  Downloading altgraph-0.17.2-py2.py3-none-any.whl (21 kB)
Installing collected packages: altgraph, pyinstaller-hooks-contrib, macholib, pyinstaller
Successfully installed altgraph-0.17.2 macholib-1.15.2 pyinstaller-4.9 pyinstaller-hooks-contrib-2022.2 WARNING: You are using pip version 21.2.3; however, version 22.0.3 is available.
You should consider upgrading via the '/Library/Frameworks/Python.framework/Versions/3.10/bin/python3 -m pip install --upgrade pip' command. 

其中的WARNING無傷大雅,先不用管。

打包失敗

現(xiàn)在我們來嘗試打包。用pyinstaller的打包過程是很簡單的。

去到058所在的文件夾,運行如下命令:

pyinstaller 058.py 

會發(fā)現(xiàn)058文件夾下多了很多內(nèi)容:

Pyinstaller打包,徹底解決圖片、數(shù)據(jù)路徑問題

其中dist目錄就是打包好的內(nèi)容所在文件夾。dist是distribution的縮寫,中文是發(fā)布的意思。

進去看看,會發(fā)現(xiàn)dist里面又有一個058文件夾,里面放著很多內(nèi)容,包括了python解釋器等。

Pyinstaller打包,徹底解決圖片、數(shù)據(jù)路徑問題

理論上,我們把整個058文件夾發(fā)給別人。

他們運行其中的058可執(zhí)行文件(圖中第一個),就可以正確執(zhí)行我們的程序。

現(xiàn)在我去雙擊一下058文件,得到的結(jié)果是:

maishu@msmacbook ~ % /Users/maishu/git/wx_maishucode/code/058/dist/058/058 ; exit;
當(dāng)前python文件所在目錄:/Users/maishu/git/wx_maishucode/code/058/dist/058
Traceback (most recent call last): File "058.py", line 5, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '/Users/maishu/git/wx_maishucode/code/058/dist/058/058.txt' [8404] Failed to execute script '058' due to unhandled exception!
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

運行失敗了:FileNotFoundError,因為數(shù)據(jù)文件沒有打包進去。

打包成功:--add-data選項

我們前面用了最簡單的打包命令,它會把python程序打包進去,不會復(fù)制數(shù)據(jù),當(dāng)然會報錯了。

實際上pyinstaller可以支持很多命令選項,我們現(xiàn)在重新打包一次,加一個選項:

pyinstaller --add-data "058.txt:." 058.py 

這里添加了--add-data "058.txt:."。解釋一下:

  • --add-data表示后面要添加數(shù)據(jù)文件
  • 058.txt是要添加的數(shù)據(jù)文件,它后面的冒號以及后面的點.表示把這個文件添加到當(dāng)前目錄下。
  • 也就是說添加文件是成對出現(xiàn),前面是要添加的文件,后面是添加的目標(biāo)目錄,中間用冒號隔開。
  • 可以添加多個文件,用分號隔開。

運行上面命令,會發(fā)現(xiàn)dist目錄下多了數(shù)據(jù)文件:

Pyinstaller打包,徹底解決圖片、數(shù)據(jù)路徑問題

然后去運行058可執(zhí)行文件:

maishu@msmacbook ~ % /Users/maishu/git/wx_maishucode/code/058/dist/058/058 ; exit;
當(dāng)前python文件所在目錄:/Users/maishu/git/wx_maishucode/code/058/dist/058
跟麥?zhǔn)甯愣窂絾栴}
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

成功了??!

打成獨立的文件:--onefile

上面是打包成了一個文件夾,發(fā)送給別人還是有點麻煩的。我們也可以直接打包成一個單獨的文件:

pyinstaller --add-data "058.txt:." --onefile 058.py 

我們加了--onefile選項,表示打包成1個獨立的文件。

運行后發(fā)現(xiàn)dist下面干凈多了:

Pyinstaller打包,徹底解決圖片、數(shù)據(jù)路徑問題

運行一下,也能成功執(zhí)行:

maishu@msmacbook ~ % /Users/maishu/git/wx_maishucode/code/058/dist/058 ; exit;
當(dāng)前python文件所在目錄:/private/var/folders/jw/ldvymnfj1zbbmngx3p8_zl_m0000gn/T/_MEIMaXGJM
跟麥?zhǔn)甯愣窂絾栴}
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

解決更復(fù)雜的問題之路

pyinstaller有很多選項,我們在解決問題的時候可能會碰到更復(fù)雜的問題,我們3分鐘講不完。

如果你希望我更深入講解,可以轉(zhuǎn)發(fā),點贊,嘻嘻。如果閱讀和評論多,我可以考慮后續(xù)再出一個Pyinstaller終結(jié)者深度文章。

但是這里我就先指明幾個方向,幫助你更有效的研究:

  • pyinstaller的官網(wǎng)上有很細致的講解:https://pyinstaller.readthedocs.io/en/stable/spec-files.html。英語不好也可以用谷歌翻譯。
  • pyinstaller打包的時候會首先生成一個spec文件,我們可以手工去修改這個文件,下次打包指定用這個文件。它的好處是:里面可以寫更復(fù)雜的選項,也可以重錄利用。spec文件的內(nèi)容例子:# -*- mode: python ; coding: utf-8 -*-
    block_cipher = None
    a = Analysis(['058.py'],
    pathex=[],binaries=[],datas=[('058.txt''.')],
    hiddenimports=[],hookspath=[],hooksconfig={},runtime_hooks=[],excludes=[],win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,noarchive=False)
    pyz = PYZ(a.pure, a.zipped_data,cipher=block_cipher)exe = EXE(pyz,a.scripts, [],exclude_binaries=True,
    name='058',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=True,
    disable_windowed_traceback=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None )
    coll = COLLECT(exe,a.binaries,a.zipfiles,a.datas, strip=False,
    upx=True,
    upx_exclude=[],name='058')

數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務(wù)器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }