Python?3.x踩坑實戰(zhàn)匯總
紀要
本文用于記錄學(xué)習(xí) Python 過程中遇到的一些小問題,如果遇到的是比較大的問題會單獨開頁面分析學(xué)習(xí)
處處有坑
1. 文件讀取 open
# 我們打開文件使用 open 方法
xml = open("demo.xml")
# 使用 open 命令讀取文件時,經(jīng)常會出現(xiàn)下列錯誤
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)這個錯誤的原因是系統(tǒng)默認打開的編碼方式和文件不一致,需要通過帶格式參數(shù)的方式打開
# 比如,文件如果是 utf-8 格式文件,則需要采用下列格式參數(shù):
xml = open("demo.xml", encoding="utf-8")2. 正則表達式 \S 與 \\S
首先提出一個問題,使用正則表達式獲取到字符串中的郵箱列表。 例:A message from csev@umich.edu to cwen@iupui.edu about meeting @2PM
# 我們可以通過一個簡單的正則表達式,這里不考慮其他復(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),下列正則表達式也有同樣的結(jié)果
lst2 = re.findall('\\S+@\\S+', s)
print(lst2)這就比較奇怪了,因為在其他語言的正則表達式中,\S 和 \\S 代表的含義并不相同,\S 表示一個非空字符,而 \\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 的情況并不相同,通過一番查詢,找到了下面的文章:
文中提到
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)義和正則表達式級別的字符串轉(zhuǎn)義。由于 s 在 Python 不是可轉(zhuǎn)義字符,解釋器將 \s 這樣的字符串理解為兩個字符 \ 和 s。將 s 替換為 n,它將其理解為換行符。
雖然沒有提及到更權(quán)威的說法,但是也反應(yīng)出了,如果是 \s 會被當做是兩個字符,如果是 \\s 因為 \\ 是可轉(zhuǎn)義字符,被當做了 \ 一個字符,\\s 也就被當做了 \s 兩個字符。所以才會出現(xiàn)這種情況。
'\s' == '\\s' # True
3. 正則表達式匹配方法 match
在學(xué)習(xí)正則表達式匹配規(guī)則時候發(fā)現(xiàn),Python 正則匹配的方式和其他的稍有不同,比如上一條提到的 \S 與 \\S 的問題,然后還有下面的:
Python 的正則匹配是從頭匹配,舉個例子,如果我們要匹配一個字符串中的電話號碼
在 JS 中你可以用下列的正則匹配
// 使用 JS 的方式,我們可以有下列的寫法
'我的手機號碼是15900000000不要告訴別人,否則我就把你號碼是13900000000告訴別人'.match(/1[0-9]{10}/g)
// (2) ['15900000000', '13900000000']但是如果你把同樣的正則放到 Python 中則不那么好使
import re
str = '我的手機號碼是15900000000不要告訴別人,否則我就把你號碼是13900000000告訴別人'
# 錯誤的寫法
mah = re.match('1[0-9]{10}', str)
print(mah)
# None因為 Python 的匹配 match 默認是從開頭開始匹配的,而 1 并不一定是給定的字符串的首字母。
# 應(yīng)該使用另一個方法 findall 代替
mah = re.findall('1[0-9]{10}', str)
print(mah)
# ['15900000000', '13900000000']從這一點可以看出,Python 的很多庫都提供用不同于其他語言的方法,作為其他語言轉(zhuǎn)學(xué) Python 的小伙伴要實際測試過方法或者熟知的情況下使用,而不應(yīng)該不加思考的定式思維,一廂情愿的覺得 Python 就和其他的語言一樣。
4. 幫助文檔 pydoc
Python 中對庫或者方法的幫助查看可以用下列的方式進行:
- 【可選】在命令行環(huán)境下輸入 python 即可進入 Python 編譯環(huán)境
- 使用
dir(庫、對象)的方式查看庫或者對象可以提供的方法
dir('字符串') # 查看字符串有哪些操作方法
import re
dir(re) # 查看正則表達式庫有哪些操作方法- 使用
help(庫、對象)的方式查看庫或者對象的幫助信息
import re help(re) # 查看正則表達式庫的幫助文檔 dir(re.match) # 查看正則表達式的 `match` 的幫助信息
如果我們是想把幫助文檔寫入文本文件中,可以在 命令行中 使用命令:
# 將 re 庫的幫助信息到 html 文檔 python -m pydoc -w re # windows 下可以用下列方法輸出到文本文件 python -m pydoc re > d:\re.txt
更多關(guān)于 pydoc 的信息可以參考官方文檔 pydoc
5. 字符串 encode base64 編碼
一些教程上對字符串的 base64 編碼的方式是這樣的:
str = "this is string example....wow!!!";
print "Encoded String: " + str.encode('base64','strict')
# 預(yù)計輸出結(jié)果
Encoded String: dGhpcyBpcyBzdHJpbmcgZXhhbXBsZS4uLi53b3chISE=但是這個代碼卻會報錯:
LookupError: 'base64' is not a text encoding; use codecs.encode() to handle arbitrary codecs
據(jù)了解,這種錯誤的寫法其實是來源于 Python 2.x 的寫法,但是在 Python 3.x 中寫法發(fā)生了變化,字符串的 base64 正確編碼方式應(yīng)該是:
import base64 str = "this is string example....wow!!!" # 返回原字符串編碼為字節(jié)串對象的版本 strb = str.encode() base64b = base64.b64encode(strb) base64 = base64b.decode() print(base64)
6. Python 調(diào)用 C# 動態(tài)鏈接庫
在百度搜索了很多關(guān)于 Python 調(diào)用 C# 動態(tài)鏈接庫的方式,大多是如下代碼:
import clr
# clr.FindAssembly('DotNetWithPython.dll') # dll在當前目錄
clr.AddReferenceToFile('DotNetWithPython.dll') # dll在當前目錄
from DotNetWithPython import * # 導(dǎo)入動態(tài)鏈接庫中的所有類
if __name__ == '__main__':
mainapp = MainForm() # 初始化 MainForm 類對象可惜啊,沒有能正常使用的,我也不清楚到底是哪里出了問題,為什么都沒有效果呢,難不成這些都是 Python 2.x 的用法嗎?(我學(xué)的是 Python 3.x)
作了如下思考:
python 的 clr 即 PythonNet,那么是否直接到 PythonNet 官方或者 github 上查找相關(guān)代碼呢?
于是搜索到了下列地址:pythonnet.github.io/按照里面給出的代碼逐個嘗試,首先是這個:
from System import String from System.Collections import *
我們發(fā)現(xiàn)會報錯:
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 *
可以確定,我們對 .NET 相關(guān)類的調(diào)用必須要 import clr 我們繼續(xù)嘗試,當嘗試到下列代碼時:
import clr from System.Drawing import Point p = Point(5, 5)
又報錯了:
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
從給出的錯誤信息中,我們可以看出,我們需要對空間進行引用:
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# 是沒有問題的,那么如果才能調(diào)用自己定義的 dll 動態(tài)鏈接庫呢?我們嘗試按照前文系統(tǒng)類的引用方式:
import clr
clr.AddReference('DotNetWithPython')
from DotNetWithPython import MainForm
mainapp = MainForm()結(jié)果報錯:
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 本身提供的類對象,調(diào)用不到我的 自己寫的動態(tài)鏈接庫和 .NET 本身提供的差異在于不在系統(tǒng)環(huán)境中,自己的 dll 在當前目錄或者其他目錄
于是我們使用 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 感覺很像,于是我們按照前文系統(tǒng)類的引用方式及這一句進行測試:
import clr
clr.FindAssembly('DotNetWithPython.dll')
clr.AddReference('DotNetWithPython')
from DotNetWithPython import MainForm
mainapp = MainForm()還是一樣的錯誤,我都要哭了,于是我只能到 PythonNet Github 的 issues 中尋找答案,發(fā)現(xiàn)提出這個問題的人很多,并且問題被鎖定在了 .net core、.net 5,而 .Net Framework 中沒有出現(xiàn)這種問題,我于是新建了一個基于 .Net Framework 4.x 的項目進行簡單測試,發(fā)現(xiàn)確實不會報錯。
現(xiàn)在問題很明確了,但是并沒有得到解決,于是我只能一條條看那難懂的 issues 列表,功夫不負有心人,我找到了這個帖子 issues 1536,明確的給出了說法,Pythonnet 2.5 does not support .NET 5、It is supported in v3 previews.。
好的吧,于是我用 pip list 查看所有 Python 第三方庫的版本
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,我對項目進行降級測試,發(fā)現(xiàn) .net core 僅在版本為 net core 1.x 時候支持,2.x-3.x、.NET 5 均不支持。
所以你如果使用的是 pythonnet 2.x 版本,就不要嘗試使用更高版本的 .net core 實現(xiàn)你的功能了,否則需要更新 pythonnet 到更高版本
繼續(xù)看 issues 1536,發(fā)現(xiàn)即使更新了版本還是會存在問題,并跟蹤到了 issues 1473 我嘗試將 pythonnet 升級到 3.x previews 版本但是出現(xiàn)的錯誤,沒有升級成功,所以并沒有繼續(xù)測試后續(xù)的功能。
總結(jié)
到此這篇關(guān)于Python 3.x踩坑實戰(zhàn)匯總的文章就介紹到這了,更多相關(guān)Python3.x踩坑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
pandas map(),apply(),applymap()區(qū)別解析
這篇文章主要介紹了pandas map(),apply(),applymap()區(qū)別解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Tensorflow 定義變量,函數(shù),數(shù)值計算等名字的更新方式
今天小編就為大家分享一篇Tensorflow 定義變量,函數(shù),數(shù)值計算等名字的更新方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02

