Python 3.x踩坑实战汇总
作者:程序园丁 发布时间:2021-04-21 12:25:47
纪要
本文用于记录学习 Python 过程中遇到的一些小问题,如果遇到的是比较大的问题会单独开页面分析学习
处处有坑
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 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']
# 然而我们发现,下列正则表达式也有同样的结果
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
我们发现 \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 re
str = '我的手机号码是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 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
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 base64
str = "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 String
from 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 clr
from System import String
from System.Collections import *
可以确定,我们对 .NET 相关类的调用必须要 import clr
我们继续尝试,当尝试到下列代码时:
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 调用 C# 是没有问题的,那么如果才能调用自己定义的 dll 动态链接库呢?我们尝试按照前文系统类的引用方式:
import clr
clr.AddReference('DotNetWithPython')
from DotNetWithPython import MainForm
mainapp = 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 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']
我们发现了方法 FindAssembly
感觉很像,于是我们按照前文系统类的引用方式及这一句进行测试:
import clr
clr.FindAssembly('DotNetWithPython.dll')
clr.AddReference('DotNetWithPython')
from DotNetWithPython import MainForm
mainapp = 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 版本但是出现的错误,没有升级成功,所以并没有继续测试后续的功能。
来源:https://juejin.cn/post/7072639020416630792


猜你喜欢
- selenium主要是用来做自动化测试,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。模拟浏览器进行网页加载,当reque
- 为了更好的进行封装,每个实现不同功能的js代码应该有自己的js文件,这样如果一个网页中引用了多个js文件,如下 <script typ
- 我们在页面进行pdf预览的时候,由于有些文件不能够进行打印和下载,这时候我们使用window自带的pdf就很难满足客户的需求,因此需要另外的
- MySQL中group_concat函数,完整的语法如下:group_concat([DISTINCT] 要连接的字段 [Order BY
- 在MySQL中,如何实现Top N及M至N段的记录查询?我们可以利用MySQL中SELECT支持的一个子句——LIMIT——来完成这项功能。
- 问题背景在开始正文之前,感谢用户名为怜索的朋友送给了我的博客2021年的第一个赞!import numpy as npimport matp
- python模块中的__all__属性,可用于模块导入时限制,如:from module import *此时被导入模块若定义了__all_
- 目录1.Python语法错误2.Python运行时错误前言:开发人员在编写程序时,难免会遇到错误,有的是编写人员疏忽造成的语法错误,有的是程
- 如下所示:import numpy as npnp.set_printoptions(threshold='nan')来源:
- Pytorch系列是了解与使用Pytorch编程来实现卷积神经网络。学习如何对卷积神经网络编程;首先,需要了解Pytorch对数据的使用(也
- 经常使用word办公的小伙伴们经常会遇到邮件合并的任务,通常会将数量有限的表格中的信息通过word的邮件合并功能,自动生成word文档,操作
- 本文是OpenCV图像视觉入门之路的第11篇文章,本文详细的在图像形态学进行了图像处理,例如:腐蚀操作、膨胀操作、开闭运算、梯度运算、Top
- 今天使用bootstrap和metroui设计了一个metro风格的移动app或者微信微网站的界面程序的源代码可以从此处获得:https:/
- 本文实例讲述了python+Django+pycharm+mysql 搭建首个web项目。分享给大家供大家参考,具体如下:前面的文章记录了环
- 1、什么是数据库连接池就是一个容器持有多个数据库连接,当程序需要操作数据库的时候直接从池中取出连接,使用完之后再还回去,和线程池一个道理。2
- 返回页面的类容,weburl为页面urlFunction GetBytes(weburl) '创建
- 话不多说,直接看示例首先是图片标记的写法<img data-src="/images/image.jpg" alt
- 网络上关于各种语言和应用软件的速查手册和快速参考指南有很多很多,不幸的是当我们需要的时候,总是很难找到,所以我决定花点时间尽可能的收集更多的
- “正则表达式”对象,我们就可以非常方便的对各种数据进行合法性的校验了。首先,让我们来了解一下究竟什么
- 本文只有代码,介绍了有关GUI界面的学生信息管理系统的实现。已经过调试没有很大问题。如有错误,还请批评指正。1.导入tkinter模块imp