日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

Python?3.x踩坑實(shí)戰(zhàn)匯總_python

作者:程序園丁 ? 更新時(shí)間: 2022-05-24 編程語言

紀(jì)要

本文用于記錄學(xué)習(xí) Python 過程中遇到的一些小問題,如果遇到的是比較大的問題會(huì)單獨(dú)開頁面分析學(xué)習(xí)

處處有坑

1. 文件讀取 open

# 我們打開文件使用 open 方法
xml = open("demo.xml")
# 使用 open 命令讀取文件時(shí),經(jīng)常會(huì)出現(xiàn)下列錯(cuò)誤
Traceback (most recent call last):
  File "TempConvert.py", line 84, in 
    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)打開的編碼方式和文件不一致,需要通過帶格式參數(shù)的方式打開
# 比如,文件如果是 utf-8 格式文件,則需要采用下列格式參數(shù):
xml = open("demo.xml", encoding="utf-8")

2. 正則表達(dá)式 \S 與 \\S

首先提出一個(gè)問題,使用正則表達(dá)式獲取到字符串中的郵箱列表。 例:A message from csev@umich.edu to cwen@iupui.edu about meeting @2PM

# 我們可以通過一個(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言的正則表達(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 的情況并不相同,通過一番查詢,找到了下面的文章:

Python regex '\s' vs '\s'

文中提到

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,它將其理解為換行符。

雖然沒有提及到更權(quán)威的說法,但是也反應(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 的問題,然后還有下面的:

Python 的正則匹配是從頭匹配,舉個(gè)例子,如果我們要匹配一個(gè)字符串中的電話號(hào)碼

在 JS 中你可以用下列的正則匹配

// 使用 JS 的方式,我們可以有下列的寫法
'我的手機(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ò)誤的寫法
mah = re.match('1[0-9]{10}', str)
print(mah)
# None

因?yàn)?Python 的匹配 match 默認(rèn)是從開頭開始匹配的,而 1 并不一定是給定的字符串的首字母。

# 應(yīng)該使用另一個(gè)方法 findall 代替
mah = re.findall('1[0-9]{10}', str)
print(mah)
# ['15900000000', '13900000000']

從這一點(diǎn)可以看出,Python 的很多庫都提供用不同于其他語言的方法,作為其他語言轉(zhuǎn)學(xué) Python 的小伙伴要實(shí)際測(cè)試過方法或者熟知的情況下使用,而不應(yīng)該不加思考的定式思維,一廂情愿的覺得 Python 就和其他的語言一樣。

4. 幫助文檔 pydoc

Python 中對(duì)庫或者方法的幫助查看可以用下列的方式進(jìn)行:

  • 【可選】在命令行環(huán)境下輸入 python 即可進(jìn)入 Python 編譯環(huán)境
  • 使用 dir(庫、對(duì)象) 的方式查看庫或者對(duì)象可以提供的方法
dir('字符串') # 查看字符串有哪些操作方法

import re
dir(re) # 查看正則表達(dá)式庫有哪些操作方法
  • 使用 help(庫、對(duì)象) 的方式查看庫或者對(duì)象的幫助信息
import re
help(re) # 查看正則表達(dá)式庫的幫助文檔
dir(re.match) # 查看正則表達(dá)式的 `match` 的幫助信息

如果我們是想把幫助文檔寫入文本文件中,可以在 命令行中 使用命令:

# 將 re 庫的幫助信息到 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ò)誤的寫法其實(shí)是來源于 Python 2.x 的寫法,但是在 Python 3.x 中寫法發(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)鏈接庫

在百度搜索了很多關(guān)于 Python 調(diào)用 C# 動(dòng)態(tài)鏈接庫的方式,大多是如下代碼:

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)鏈接庫中的所有類

if __name__ == '__main__':
    mainapp = MainForm() # 初始化 MainForm 類對(duì)象

可惜啊,沒有能正常使用的,我也不清楚到底是哪里出了問題,為什么都沒有效果呢,難不成這些都是 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
? ? from System import String
ModuleNotFoundError: No module named 'System'

我們嘗試把代碼修改為:

import clr
from System import String
from System.Collections import *

可以確定,我們對(duì) .NET 相關(guān)類的調(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# 是沒有問題的,那么如果才能調(diào)用自己定義的 dll 動(dòng)態(tài)鏈接庫呢?我們嘗試按照前文系統(tǒng)類的引用方式:

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
? ? from DotNetWithPython import MainForm
ModuleNotFoundError: No module named 'DotNetWithPython'

于是我又想:

clr 可以正常調(diào)用 .NET 本身提供的類對(duì)象,調(diào)用不到我的 自己寫的動(dòng)態(tài)鏈接庫和 .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 感覺很像,于是我們按照前文系統(tǒng)類的引用方式及這一句進(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è)問題的人很多,并且問題被鎖定在了 .net core、.net 5,而 .Net Framework 中沒有出現(xiàn)這種問題,我于是新建了一個(gè)基于 .Net Framework 4.x 的項(xiàng)目進(jìn)行簡(jiǎn)單測(cè)試,發(fā)現(xiàn)確實(shí)不會(huì)報(bào)錯(cuò)。

現(xiàn)在問題很明確了,但是并沒有得到解決,于是我只能一條條看那難懂的 issues 列表,功夫不負(fù)有心人,我找到了這個(gè)帖子 issues 1536,明確的給出了說法,Pythonnet 2.5 does not support .NET 5It 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,我對(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ì)存在問題,并跟蹤到了 issues 1473 我嘗試將 pythonnet 升級(jí)到 3.x previews 版本但是出現(xiàn)的錯(cuò)誤,沒有升級(jí)成功,所以并沒有繼續(xù)測(cè)試后續(xù)的功能。

總結(jié)

原文鏈接:https://juejin.cn/post/7072639020416630792

欄目分類
最近更新