这篇文章主要为大家展示了“Python 3.x踩坑的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Python 3.x踩坑的示例分析”这篇文章吧。
处处有坑
1. 文件读取 open
# 我们打开文件使用 open 方法xml = open("demo.xml")# 使用 open 命令读取文件时,经常会出现下列错误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
# 出现这个错误的原因是系统默认打开的编码方式和文件不一致,需要通过带格式参数的方式打开# 比如,文件如果是 utf-8 格式文件,则需要采用下列格式参数:xml = open("demo.xml", encoding="utf-8")
2. 正则表达式 \S 与 \\S
首先提出一个问题,使用正则表达式获取到字符串中的邮箱列表。 例:A message from csev@umich.edu to cwen@iupui.edu about meeting @2PM
# 我们可以通过一个简单的正则表达式,这里不考虑其他复杂条件import restr = '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']# 然而我们发现,下列正则表达式也有同样的结果lst2 = re.findall('\\S+@\\S+', s)print(lst2)
这就比较奇怪了,因为在其他语言的正则表达式中,\S
和 \\S
代表的含义并不相同,\S
表示一个非空字符,而 \\S
表示匹配字符串 \S
,于是我们作下列尝试:
'\S' == '\\S' # Truelen('\\S') # 2len('\S') # 2
是不是惊呆了!于是我又尝试
'\s' == '\\s' # Truelen('\\s') # 2len('\s') # 2'\n' == '\\n' # Falselen('\\n') # 2len('\n') # 1
我们发现 \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 中的字符串转义和正则表达式级别的字符串转义。由于 s 在 Python 不是可转义字符,解释器将 \s 这样的字符串理解为两个字符 \ 和 s。将 s 替换为 n,它将其理解为换行符。
虽然没有提及到更权威的说法,但是也反应出了,如果是 \s
会被当做是两个字符,如果是 \\s
因为 \\
是可转义字符,被当做了 \
一个字符,\\s
也就被当做了 \s
两个字符。所以才会出现这种情况。
'\s' == '\\s' # True
3. 正则表达式匹配方法 match
在学习正则表达式匹配规则时候发现,Python 正则匹配的方式和其他的稍有不同,比如上一条提到的 \S
与 \\S
的问题,然后还有下面的:
Python 的正则匹配是从头匹配,举个例子,如果我们要匹配一个字符串中的电话号码
在 JS 中你可以用下列的正则匹配
// 使用 JS 的方式,我们可以有下列的写法'我的手机号码是15900000000不要告诉别人,否则我就把你号码是13900000000告诉别人'.match(/1[0-9]{10}/g)// (2) ['15900000000', '13900000000']
但是如果你把同样的正则放到 Python 中则不那么好使
import restr = '我的手机号码是15900000000不要告诉别人,否则我就把你号码是13900000000告诉别人'# 错误的写法mah = re.match('1[0-9]{10}', str)print(mah)# None
因为 Python 的匹配 match
默认是从开头开始匹配的,而 1 并不一定是给定的字符串的首字母。
# 应该使用另一个方法 findall 代替mah = re.findall('1[0-9]{10}', str)print(mah)# ['15900000000', '13900000000']
从这一点可以看出,Python 的很多库都提供用不同于其他语言的方法,作为其他语言转学 Python 的小伙伴要实际测试过方法或者熟知的情况下使用,而不应该不加思考的定式思维,一厢情愿的觉得 Python 就和其他的语言一样。
4. 帮助文档 pydoc
Python 中对库或者方法的帮助查看可以用下列的方式进行:
【可选】在命令行环境下输入 python 即可进入 Python 编译环境
使用
dir(库、对象)
的方式查看库或者对象可以提供的方法
dir('字符串') # 查看字符串有哪些操作方法import redir(re) # 查看正则表达式库有哪些操作方法
使用
help(库、对象)
的方式查看库或者对象的帮助信息
import rehelp(re) # 查看正则表达式库的帮助文档dir(re.match) # 查看正则表达式的 `match` 的帮助信息
如果我们是想把帮助文档写入文本文件中,可以在 命令行中 使用命令:
# 将 re 库的帮助信息到 html 文档python -m pydoc -w re# windows 下可以用下列方法输出到文本文件python -m pydoc re > d:\re.txt
更多关于 pydoc 的信息可以参考官方文档 pydoc
5. 字符串 encode base64 编码
一些教程上对字符串的 base64 编码的方式是这样的:
str = "this is string example....wow!!!";print "Encoded String: " + str.encode('base64','strict')# 预计输出结果Encoded String: dGhpcyBpcyBzdHJpbmcgZXhhbXBsZS4uLi53b3chISE=
但是这个代码却会报错:
LookupError: 'base64' is not a text encoding; use codecs.encode() to handle arbitrary codecs
据了解,这种错误的写法其实是来源于 Python 2.x 的写法,但是在 Python 3.x 中写法发生了变化,字符串的 base64 正确编码方式应该是:
import base64str = "this is string example....wow!!!"# 返回原字符串编码为字节串对象的版本strb = str.encode()base64b = base64.b64encode(strb)base64 = base64b.decode()print(base64)
6. Python 调用 C# 动态链接库
在百度搜索了很多关于 Python 调用 C# 动态链接库的方式,大多是如下代码:
import clr# clr.FindAssembly('DotNetWithPython.dll') # dll在当前目录clr.AddReferenceToFile('DotNetWithPython.dll') # dll在当前目录from DotNetWithPython import * # 导入动态链接库中的所有类if __name__ == '__main__': mainapp = MainForm() # 初始化 MainForm 类对象
可惜啊,没有能正常使用的,我也不清楚到底是哪里出了问题,为什么都没有效果呢,难不成这些都是 Python 2.x 的用法吗?(我学的是 Python 3.x)
作了如下思考:
python 的 clr 即 PythonNet,那么是否直接到 PythonNet 官方或者 github 上查找相关代码呢?
于是搜索到了下列地址:pythonnet.github.io/按照里面给出的代码逐个尝试,首先是这个:
from System import Stringfrom System.Collections import *
我们发现会报错:
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 clrfrom System import Stringfrom System.Collections import *
可以确定,我们对 .NET 相关类的调用必须要 import clr
我们继续尝试,当尝试到下列代码时:
import clrfrom System.Drawing import Pointp = 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 clrclr.AddReference('System.Drawing')from System.Drawing import Pointp = Point(5, 5)print(p)# {X=5,Y=5}
到了这一步,我们基本确定 Python 调用 C# 是没有问题的,那么如果才能调用自己定义的 dll 动态链接库呢?我们尝试按照前文系统类的引用方式:
import clrclr.AddReference('DotNetWithPython')from DotNetWithPython import MainFormmainapp = MainForm()
结果报错:
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 可以正常调用 .NET 本身提供的类对象,调用不到我的 自己写的动态链接库和 .NET 本身提供的差异在于不在系统环境中,自己的 dll 在当前目录或者其他目录
于是我们使用 dir(clr)
确定了一下是否有什么方法可用
import clrdir(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']
我们发现了方法 FindAssembly
感觉很像,于是我们按照前文系统类的引用方式及这一句进行测试:
import clrclr.FindAssembly('DotNetWithPython.dll')clr.AddReference('DotNetWithPython')from DotNetWithPython import MainFormmainapp = MainForm()
还是一样的错误,我都要哭了,于是我只能到 PythonNet Github 的 issues 中寻找答案,发现提出这个问题的人很多,并且问题被锁定在了 .net core、.net 5,而 .Net Framework 中没有出现这种问题,我于是新建了一个基于 .Net Framework 4.x 的项目进行简单测试,发现确实不会报错。
现在问题很明确了,但是并没有得到解决,于是我只能一条条看那难懂的 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,我对项目进行降级测试,发现 .net core 仅在版本为 net core 1.x 时候支持,2.x-3.x、.NET 5 均不支持。
所以你如果使用的是 pythonnet 2.x 版本,就不要尝试使用更高版本的 .net core 实现你的功能了,否则需要更新 pythonnet 到更高版本
继续看 issues 1536,发现即使更新了版本还是会存在问题,并跟踪到了 issues 1473 我尝试将 pythonnet 升级到 3.x previews 版本但是出现的错误,没有升级成功,所以并没有继续测试后续的功能。
以上是“Python 3.x踩坑的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!