Python?3.x踩坑實(shí)戰(zhàn)匯總
紀(jì)要
本文用于記錄學(xué)習(xí) Python 過(guò)程中遇到的一些小問(wèn)題,如果遇到的是比較大的問(wèn)題會(huì)單獨(dú)開(kāi)頁(yè)面分析學(xué)習(xí)
處處有坑
1. 文件讀取 open
# 我們打開(kāi)文件使用 open 方法 xml = open("demo.xml") # 使用 open 命令讀取文件時(shí),經(jīng)常會(huì)出現(xiàn)下列錯(cuò)誤 Traceback (most recent call last): File "TempConvert.py", line 84, in <module> for line in xml: UnicodeDecodeError: 'gbk' codec can't decode byte 0x8d in position 38: illegal multibyte sequence
# 出現(xiàn)這個(gè)錯(cuò)誤的原因是系統(tǒng)默認(rèn)打開(kāi)的編碼方式和文件不一致,需要通過(guò)帶格式參數(shù)的方式打開(kāi) # 比如,文件如果是 utf-8 格式文件,則需要采用下列格式參數(shù): xml = open("demo.xml", encoding="utf-8")
2. 正則表達(dá)式 \S 與 \\S
首先提出一個(gè)問(wèn)題,使用正則表達(dá)式獲取到字符串中的郵箱列表。 例:A message from csev@umich.edu to cwen@iupui.edu about meeting @2PM
# 我們可以通過(guò)一個(gè)簡(jiǎn)單的正則表達(dá)式,這里不考慮其他復(fù)雜條件 import re str = 'A message from csev@umich.edu to cwen@iupui.edu about meeting @2PM' lst1 = re.findall('\S+@\S+', s) print(lst1) # ['csev@umich.edu', 'cwen@iupui.edu'] # 然而我們發(fā)現(xiàn),下列正則表達(dá)式也有同樣的結(jié)果 lst2 = re.findall('\\S+@\\S+', s) print(lst2)
這就比較奇怪了,因?yàn)樵谄渌Z(yǔ)言的正則表達(dá)式中,\S
和 \\S
代表的含義并不相同,\S
表示一個(gè)非空字符,而 \\S
表示匹配字符串 \S
,于是我們作下列嘗試:
'\S' == '\\S' # True len('\\S') # 2 len('\S') # 2
是不是驚呆了!于是我又嘗試
'\s' == '\\s' # True len('\\s') # 2 len('\s') # 2 '\n' == '\\n' # False len('\\n') # 2 len('\n') # 1
我們發(fā)現(xiàn) \s
和 \n
的情況并不相同,通過(guò)一番查詢(xún),找到了下面的文章:
文中提到
Don't confuse python-level string-escaping and regex-level string-escaping. Since s is not an escapable character at python-level, the interpreter understand a string like \s as the two characters \ and s. Replace s with n, and it understands it as the newline character.
不要混淆 Python 中的字符串轉(zhuǎn)義和正則表達(dá)式級(jí)別的字符串轉(zhuǎn)義。由于 s 在 Python 不是可轉(zhuǎn)義字符,解釋器將 \s 這樣的字符串理解為兩個(gè)字符 \ 和 s。將 s 替換為 n,它將其理解為換行符。
雖然沒(méi)有提及到更權(quán)威的說(shuō)法,但是也反應(yīng)出了,如果是 \s
會(huì)被當(dāng)做是兩個(gè)字符,如果是 \\s
因?yàn)?\\
是可轉(zhuǎn)義字符,被當(dāng)做了 \
一個(gè)字符,\\s
也就被當(dāng)做了 \s
兩個(gè)字符。所以才會(huì)出現(xiàn)這種情況。
'\s' == '\\s' # True
3. 正則表達(dá)式匹配方法 match
在學(xué)習(xí)正則表達(dá)式匹配規(guī)則時(shí)候發(fā)現(xiàn),Python 正則匹配的方式和其他的稍有不同,比如上一條提到的 \S
與 \\S
的問(wèn)題,然后還有下面的:
Python 的正則匹配是從頭匹配,舉個(gè)例子,如果我們要匹配一個(gè)字符串中的電話號(hào)碼
在 JS 中你可以用下列的正則匹配
// 使用 JS 的方式,我們可以有下列的寫(xiě)法 '我的手機(jī)號(hào)碼是15900000000不要告訴別人,否則我就把你號(hào)碼是13900000000告訴別人'.match(/1[0-9]{10}/g) // (2) ['15900000000', '13900000000']
但是如果你把同樣的正則放到 Python 中則不那么好使
import re str = '我的手機(jī)號(hào)碼是15900000000不要告訴別人,否則我就把你號(hào)碼是13900000000告訴別人' # 錯(cuò)誤的寫(xiě)法 mah = re.match('1[0-9]{10}', str) print(mah) # None
因?yàn)?Python 的匹配 match
默認(rèn)是從開(kāi)頭開(kāi)始匹配的,而 1 并不一定是給定的字符串的首字母。
# 應(yīng)該使用另一個(gè)方法 findall 代替 mah = re.findall('1[0-9]{10}', str) print(mah) # ['15900000000', '13900000000']
從這一點(diǎn)可以看出,Python 的很多庫(kù)都提供用不同于其他語(yǔ)言的方法,作為其他語(yǔ)言轉(zhuǎn)學(xué) Python 的小伙伴要實(shí)際測(cè)試過(guò)方法或者熟知的情況下使用,而不應(yīng)該不加思考的定式思維,一廂情愿的覺(jué)得 Python 就和其他的語(yǔ)言一樣。
4. 幫助文檔 pydoc
Python 中對(duì)庫(kù)或者方法的幫助查看可以用下列的方式進(jìn)行:
- 【可選】在命令行環(huán)境下輸入 python 即可進(jìn)入 Python 編譯環(huán)境
- 使用
dir(庫(kù)、對(duì)象)
的方式查看庫(kù)或者對(duì)象可以提供的方法
dir('字符串') # 查看字符串有哪些操作方法 import re dir(re) # 查看正則表達(dá)式庫(kù)有哪些操作方法
- 使用
help(庫(kù)、對(duì)象)
的方式查看庫(kù)或者對(duì)象的幫助信息
import re help(re) # 查看正則表達(dá)式庫(kù)的幫助文檔 dir(re.match) # 查看正則表達(dá)式的 `match` 的幫助信息
如果我們是想把幫助文檔寫(xiě)入文本文件中,可以在 命令行中 使用命令:
# 將 re 庫(kù)的幫助信息到 html 文檔 python -m pydoc -w re # windows 下可以用下列方法輸出到文本文件 python -m pydoc re > d:\re.txt
更多關(guān)于 pydoc 的信息可以參考官方文檔 pydoc
5. 字符串 encode base64 編碼
一些教程上對(duì)字符串的 base64 編碼的方式是這樣的:
str = "this is string example....wow!!!"; print "Encoded String: " + str.encode('base64','strict') # 預(yù)計(jì)輸出結(jié)果 Encoded String: dGhpcyBpcyBzdHJpbmcgZXhhbXBsZS4uLi53b3chISE=
但是這個(gè)代碼卻會(huì)報(bào)錯(cuò):
LookupError: 'base64' is not a text encoding; use codecs.encode() to handle arbitrary codecs
據(jù)了解,這種錯(cuò)誤的寫(xiě)法其實(shí)是來(lái)源于 Python 2.x 的寫(xiě)法,但是在 Python 3.x 中寫(xiě)法發(fā)生了變化,字符串的 base64 正確編碼方式應(yīng)該是:
import base64 str = "this is string example....wow!!!" # 返回原字符串編碼為字節(jié)串對(duì)象的版本 strb = str.encode() base64b = base64.b64encode(strb) base64 = base64b.decode() print(base64)
6. Python 調(diào)用 C# 動(dòng)態(tài)鏈接庫(kù)
在百度搜索了很多關(guān)于 Python 調(diào)用 C# 動(dòng)態(tài)鏈接庫(kù)的方式,大多是如下代碼:
import clr # clr.FindAssembly('DotNetWithPython.dll') # dll在當(dāng)前目錄 clr.AddReferenceToFile('DotNetWithPython.dll') # dll在當(dāng)前目錄 from DotNetWithPython import * # 導(dǎo)入動(dòng)態(tài)鏈接庫(kù)中的所有類(lèi) if __name__ == '__main__': mainapp = MainForm() # 初始化 MainForm 類(lèi)對(duì)象
可惜啊,沒(méi)有能正常使用的,我也不清楚到底是哪里出了問(wèn)題,為什么都沒(méi)有效果呢,難不成這些都是 Python 2.x 的用法嗎?(我學(xué)的是 Python 3.x)
作了如下思考:
python 的 clr 即 PythonNet,那么是否直接到 PythonNet 官方或者 github 上查找相關(guān)代碼呢?
于是搜索到了下列地址:pythonnet.github.io/按照里面給出的代碼逐個(gè)嘗試,首先是這個(gè):
from System import String from System.Collections import *
我們發(fā)現(xiàn)會(huì)報(bào)錯(cuò):
Traceback (most recent call last):
File "d:/Temp/PythonProjects/Demos/DllDo.py", line 10, in <module>
from System import String
ModuleNotFoundError: No module named 'System'
我們嘗試把代碼修改為:
import clr from System import String from System.Collections import *
可以確定,我們對(duì) .NET 相關(guān)類(lèi)的調(diào)用必須要 import clr
我們繼續(xù)嘗試,當(dāng)嘗試到下列代碼時(shí):
import clr from System.Drawing import Point p = Point(5, 5)
又報(bào)錯(cuò)了:
d:/Temp/PythonProjects/Demos/DllDo.py:11: DeprecationWarning: The module was found, but not in a referenced namespace.
Implicit loading is deprecated. Please use clr.AddReference('System.Drawing').
from System.Drawing import Point
從給出的錯(cuò)誤信息中,我們可以看出,我們需要對(duì)空間進(jìn)行引用:
import clr clr.AddReference('System.Drawing') from System.Drawing import Point p = Point(5, 5) print(p) # {X=5,Y=5}
到了這一步,我們基本確定 Python 調(diào)用 C# 是沒(méi)有問(wèn)題的,那么如果才能調(diào)用自己定義的 dll 動(dòng)態(tài)鏈接庫(kù)呢?我們嘗試按照前文系統(tǒng)類(lèi)的引用方式:
import clr clr.AddReference('DotNetWithPython') from DotNetWithPython import MainForm mainapp = MainForm()
結(jié)果報(bào)錯(cuò):
Traceback (most recent call last):
File "d:/Temp/PythonProjects/Demos/DllDo.py", line 12, in <module>
from DotNetWithPython import MainForm
ModuleNotFoundError: No module named 'DotNetWithPython'
于是我又想:
clr 可以正常調(diào)用 .NET 本身提供的類(lèi)對(duì)象,調(diào)用不到我的 自己寫(xiě)的動(dòng)態(tài)鏈接庫(kù)和 .NET 本身提供的差異在于不在系統(tǒng)環(huán)境中,自己的 dll 在當(dāng)前目錄或者其他目錄
于是我們使用 dir(clr)
確定了一下是否有什么方法可用
import clr dir(clr) # ['AddReference', 'FindAssembly', 'GetClrType', 'ListAssemblies', 'Microsoft', 'Python', 'System', '_AtExit', '__class__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', '_extras', 'clrModule', 'clrmethod', 'clrproperty', 'e__NativeCall', 'getPreload', 'setPreload']
我們發(fā)現(xiàn)了方法 FindAssembly
感覺(jué)很像,于是我們按照前文系統(tǒng)類(lèi)的引用方式及這一句進(jìn)行測(cè)試:
import clr clr.FindAssembly('DotNetWithPython.dll') clr.AddReference('DotNetWithPython') from DotNetWithPython import MainForm mainapp = MainForm()
還是一樣的錯(cuò)誤,我都要哭了,于是我只能到 PythonNet Github 的 issues 中尋找答案,發(fā)現(xiàn)提出這個(gè)問(wèn)題的人很多,并且問(wèn)題被鎖定在了 .net core、.net 5,而 .Net Framework 中沒(méi)有出現(xiàn)這種問(wèn)題,我于是新建了一個(gè)基于 .Net Framework 4.x 的項(xiàng)目進(jìn)行簡(jiǎn)單測(cè)試,發(fā)現(xiàn)確實(shí)不會(huì)報(bào)錯(cuò)。
現(xiàn)在問(wèn)題很明確了,但是并沒(méi)有得到解決,于是我只能一條條看那難懂的 issues 列表,功夫不負(fù)有心人,我找到了這個(gè)帖子 issues 1536,明確的給出了說(shuō)法,Pythonnet 2.5 does not support .NET 5
、It is supported in v3 previews.
。
好的吧,于是我用 pip list
查看所有 Python 第三方庫(kù)的版本
C:\Users\Administrator>pip list
Package Version
---------------- ----------
click 7.1.2
pip 22.0.3
pycparser 2.21
PyQt5 5.15.4
pyqt5-plugins 5.15.4.2.2
PyQt5-Qt5 5.15.2
PyQt5-sip 12.9.1
pyqt5-tools 5.15.4.3.2
python-dotenv 0.19.2
pythonnet 2.5.2
qt5-applications 5.15.2.2.2
qt5-tools 5.15.2.1.2
setuptools 41.2.0
果然,pythonnet 的版本是 2.5.2,我對(duì)項(xiàng)目進(jìn)行降級(jí)測(cè)試,發(fā)現(xiàn) .net core 僅在版本為 net core 1.x 時(shí)候支持,2.x-3.x、.NET 5 均不支持。
所以你如果使用的是 pythonnet 2.x 版本,就不要嘗試使用更高版本的 .net core 實(shí)現(xiàn)你的功能了,否則需要更新 pythonnet 到更高版本
繼續(xù)看 issues 1536,發(fā)現(xiàn)即使更新了版本還是會(huì)存在問(wèn)題,并跟蹤到了 issues 1473 我嘗試將 pythonnet 升級(jí)到 3.x previews 版本但是出現(xiàn)的錯(cuò)誤,沒(méi)有升級(jí)成功,所以并沒(méi)有繼續(xù)測(cè)試后續(xù)的功能。
總結(jié)
到此這篇關(guān)于Python 3.x踩坑實(shí)戰(zhàn)匯總的文章就介紹到這了,更多相關(guān)Python3.x踩坑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Python對(duì)Dicom文件進(jìn)行讀取與寫(xiě)入的實(shí)現(xiàn)
這篇文章主要介紹了使用Python對(duì)Dicom文件進(jìn)行讀取與寫(xiě)入的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04Python 從一個(gè)文件中調(diào)用另一個(gè)文件的類(lèi)方法
今天小編就為大家分享一篇Python 從一個(gè)文件中調(diào)用另一個(gè)文件的類(lèi)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01Python繪圖Turtle庫(kù)的安裝問(wèn)題解決
這篇文章主要介紹了Python繪圖中解決Turtle的安裝問(wèn)題示例分析,也遇到過(guò)相同問(wèn)題的同學(xué)可以借鑒參考下,希望能夠解決你的問(wèn)題2021-10-10Python Dict找出value大于某值或key大于某值的所有項(xiàng)方式
這篇文章主要介紹了Python Dict找出value大于某值或key大于某值的所有項(xiàng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06Pandas中DataFrame.head()函數(shù)的具體使用
DataFrame.head()是Pandas庫(kù)中一個(gè)非常重要的函數(shù),用于返回DataFrame對(duì)象的前n行,本文主要介紹了Pandas中DataFrame.head()函數(shù)的具體使用,感興趣的可以了解一下2024-07-07windows+vscode穿越跳板機(jī)調(diào)試遠(yuǎn)程代碼的圖文教程
本文通過(guò)圖文并茂的形式給大家介紹了windows+vscode穿越跳板機(jī)調(diào)試遠(yuǎn)程代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02python3爬蟲(chóng)學(xué)習(xí)之?dāng)?shù)據(jù)存儲(chǔ)txt的案例詳解
這篇文章主要介紹了python3爬蟲(chóng)學(xué)習(xí)之?dāng)?shù)據(jù)存儲(chǔ)txt的案例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04