Python 3.x踩坑实战汇总

目录
  • 纪要
  • 处处有坑
    • 1. 文件读取 open
    • 2. 正则表达式 \S 与 \\S
    • 3. 正则表达式匹配方法 match
    • 4. 帮助文档 pydoc
    • 5. 字符串 encode base64 编码
    • 6. Python 调用 C# 动态链接库
  • 总结

纪要

本文用于记录学习 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

更多关于 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 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 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,我对项目进行降级测试,发现 .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踩坑实战汇总的文章就介绍到这了,更多相关Python3.x踩坑内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Linux下安装Python3.6及避坑指南

    Python3的安装 1.安装依赖环境 Python3在安装的过程中可能会用到各种依赖库,所以在正式安装Python3之前,需要将这些依赖库先行安装好. yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel 2. 下载Python3源代码 下载Python3的

  • 浅谈python配置与使用OpenCV踩的一些坑

    下载opencv2.4.9(python2.7匹配)后 (1)运行OpenCV 2.4.9.exe: (2)配置Python:将\opencv\build\python\2.7\x64 这个目录下:cv2.pyd 复制到:Python27\Lib\site-packages\目录下: (3)测试:输入import cv2,如报错,说明未安装成功 1.opencv的版本一定要与python的版本匹配,否则是python是无法调用cv2这个模块的. 错误信息:ImportError DLL load

  • python字典和json.dumps()的遇到的坑分析

    最近项目中需要与管易云erp做对接,看了他的接口文档,php的示例代码,于是用python仿写. 其中传的参数data中前面几个json数据是固定的,最后需要加一个签名,该签名是对前面的json数据字符串化后,首尾拼接上screct字符串,再做md5处理(32位大写),再将该签名添加到之前的json中作为post参数传递过去. 问题就出在组装json字符串和签名中,因为python内置的字典是无序的,导致我组装好的json数据作为参数传递给自己编写的签名函数时,字典内部的顺序是变化的,所以签名前

  • 跟老齐学Python之坑爹的字符编码

    字符编码,在编程中,是一个让学习者比较郁闷的东西,比如一个str,如果都是英文,好说多了.但恰恰不是如此,中文是我们不得不用的.所以,哪怕是初学者,都要了解并能够解决字符编码问题. >>> name = '老齐' >>> name '\xe8\x80\x81\xe9\xbd\x90' 在你的编程中,你遇到过上面的情形吗?认识最下面一行打印出来的东西吗?看人家英文,就好多了 >>> name = "qiwsir" >>&g

  • python list删除元素时要注意的坑点分享

    我们直接先给出输出与预期不同的代码 In[28]: a = [1,2,3,4,5,6] In[29]: for i in a: ...: a.remove(i) ...: In[30]: a Out[30]: [2, 4, 6] 在上述for循环中,假设我们删除了index=2的值,原本index=3及之后的值会向前补位,所以在循环中就跳过了原index=3的变量 同理,使用list.pop()函数删除指定元素的时候,也会出现上述情况,如: In[33]: a = [1,2,3,4,5,6] I

  • Python 3.x踩坑实战汇总

    目录 纪要 处处有坑 1. 文件读取 open 2. 正则表达式 \S 与 \\S 3. 正则表达式匹配方法 match 4. 帮助文档 pydoc 5. 字符串 encode base64 编码 6. Python 调用 C# 动态链接库 总结 纪要 本文用于记录学习 Python 过程中遇到的一些小问题,如果遇到的是比较大的问题会单独开页面分析学习 处处有坑 1. 文件读取 open # 我们打开文件使用 open 方法 xml = open("demo.xml") # 使用 op

  • 使用Pyinstaller的最新踩坑实战记录

    前言 将py编译成可执行文件需要使用PyInstaller,之前给大家介绍了关于利用PyInstaller将python程序.py转为.exe的方法,在开始本文之前推荐大家可以先看下这篇文章,本文主要给大家介绍了Pyinstaller最新踩坑实战记录,现在网上关于pyinstaller的问题充斥着各种copy过来copy过去的答案,这大概就是各种无脑博客爬虫站最让人讨厌的地方. 而且这方面的问题,stackoverflow也是回答的千奇百怪. 强烈推荐官方文档 http://pythonhost

  • Go使用proto3的踩坑实战记录

    开发环境:windows10,golang1.18.2,goland2022.2 最近在写项目时,一些数据类的结构以protobuf文件给定.因此,需要将这些protobuf文件转换为golang代码. 首先,在下载解析protobuf的包的时候就碰到了第一个问题... go get -u github.com/golang/protobuf/protoc-gen-go 在我用上述命令后,终端提示该包已弃用 go: module github.com/golang/protobuf is dep

  • C++踩坑实战之构造和析构函数

    目录 前言 构造函数 通过构造函数实现的类型转换 派生类的构造函数 析构函数 继承中的析构函数 应用 总结 前言 我是练习时长一年的 C++ 个人练习生,喜欢野指针.模板报错和未定义行为(undefined behavior).之前在写设计模式的『工厂模式』时,一脚踩到了构造.继承和 new 组合起来的坑,现在也有时间来整理一下了. 构造函数 众所周知:在创建对象时,防止有些成员没有被初始化导致不必要的错误,在创建对象的时候自动调用构造函数(无声明类型),完成成员的初始化.即: Class c

  • Swift踩坑实战之一个字符引发的Crash

    最近因为一个字符引发了 Crash,因为实际的业务场景不便描述,这里便用一段测试代码作说明. 话不多说,直接上代码: let testCharacters: Set<Character> = ["!", "\"", "$", "%", "&", "'", "+", ",", "<", &quo

  • nginx反向代理踩坑实战记录(容器方式)

    目录 一.简述 1.1 什么是反向代理? 1.2 看图理解 1.3 错误总结 二.正确案例 2.1 启动nginx 2.3 配置nginx 2.4 重启所有服务 2.5 测试 三.云服务器上跑的nginx怎么代理本地项目 总结 一.简述 1.1 什么是反向代理? 这很重要,反向代理就是代理服务器代理真实服务器.客户端以为代理服务器就是真实服务器,所以就会把要请求的==资源(URL)==发给代理服务器. 代理服务器一般是由nginx来充当,代理功能由配置文件来完成. 1.2 看图理解 画的仓促,大

  • 一场由Java中Integer引发的踩坑实战

    看过阿里巴巴开发手册的同学应该都会对Integer临界值127有点印象. 原文中写的是: [强制]所有整型包装类对象之间值的比较,全部使用 equals 方法比较. 说明:对于 Integer var = ? 在-128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生, 会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都 会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法

  • Ruoyi从mysql切换到postgresql的几个踩坑实战

    目录 前言 一.在pom.xml文件中将mysql的依赖jar包替换成postgresql的. 二.mybatis-plus或者分页插件数据库类别支持 三.数据库连接池要做相应调整 四.自动任务依赖,如果您开启了quartz组件,请记得打开以下注释 五.在所有的Mapper.xml配置文件中,找到有sysdate()的函数,需要替换成now()函数. 六.所有带日期查询函数需要替换成如下的代码: 七.mysql find_in_set()函数可以使用ANY()方案. 总结: 前言 因为工程应用需

  • Android中EditText setText方法的踩坑实战

    1.平平常常中就这样开始 某一天,我准备做一个搜索功能,这个搜索功能呢大概是在主活动A中,用EditText接收输入,当EditText监听到输入框中内容有变化,跳转到活动B中,活动B中准备有搜索历史记录等等,等在活动B中确定好搜索关键词后,跳回到活动A中,执行搜索,并显示搜索结果--一切顺顺利利,然后呢,懵逼了,我回不了活动A了. 当时的情况大致是这样的, 布局文件:activity_main.xml <?xml version="1.0" encoding="utf

  • 一次mysql迁移的方案与踩坑实战记录

    目录 背景 方案一:老数据备份 方案二:分表 方案三:迁移至tidb 重点说下同步老数据遇到的坑 最终同步脚本方案 总结 背景 由于历史业务数据采用mysql来存储的,其中有一张操作记录表video_log,每当用户创建.更新或者审核人员审核的时候,对应的video_log就会加一条日志,这个log表只有insert,可想而知,1个video对应多条log,一天10w video,平均统计一个video对应5条log,那么一天50w的log, 一个月50 * 30 = 1500w条记录, 一年就

随机推荐