python读取ansi_关于Python,那些年我们一起踩过的坑

936d78734899a4c647e071f133ae79a3.png

Python,语法简,故入门速;模块多,所以应用广。于是专业程序猿用之,数据从业者趋之,以至中学师生学之。一时乐之、好之者众多,颇有全民之势。然金无足赤,自古语言之争,盖无定论。于Python,虽多有褒词,习之亦有数坑,探得一二,诸位慎之、避之。

1)round函数:保留小数指定位数(默认只整数),但不保证四舍五入

这里保留小数的位数没有问题,但是末位为5,进还是舍是有些坑的。

615851b7015397264bb9bd31eef812a0.png

你以为Python为了公平进舍,搞了个四舍六入五靠双?好像有点道理,但随着小数位数的增多,这个原则就不通用了:

98563caff6a8896ebb57c20f971cb4e3.png

在此我们不深究原因了,大概就是浮点数转二进制保存时,有时是无限制长的,只能截断。导致存起来的真实数据可能就偏小,我们用Decimal数据类型来看看真实的2.675:

2b17308732c85151a3fbecdd0762212f.png

所以round的时候保留两位,也就成了2.64。

如果你的程序不会因为这个受太大影响,倒也无所谓了。如果你就是要四舍五入的效果,也很简单,自己写个函数截取判断修改就行。

2)+与+=:看起来等价,其实可能未必等价

很多人受多语言影响,喜欢把a=a+1简写做a+=1,Python语法也是支持这么做的。但是有些时候,这两者还是有区别的:

看看这个这个写法,猜一下结果。

a=[1,2,3]b=aa=a+[4,5]print(a,b)

8547f296c729c7c46b95ca515738f316.png

于是我们反推一下,肯定是这样:

b=a则b指向了a指向的列表空间。a+[4,5]形成了一个新的列表空间,a重新指向了它。

从结果来看,没毛病。所以想当然的,改一下:

a=[1,2,3]b=aa+=[4,5]print(a,b)

20b0faa94501bdf3a912ad749c6f4952.png

好吧,其实不太一样:

+=相当于列表的extend方法,是在原来的空间扩展。就好像列表中append一个新元素一样。

另外有人测试过,+=连接字符串的速度要明显快些。

3)列表遍历删除元素:remove删除的不光是数据,还有“位置”

def test(data):    for i in data:        data.remove(i)    return datadata = [1, 2, 3]print(test(data))

按说应该输出空列表,然而并没有:

e383b196b801e977a9f780d8c6ad06fc.png

为什么会产生这种结果呢? 假设原列表在内存中为:

3b446ba4b875230ad3753eafd93af062.png

第一次执行到data.remove(i)时将第一个元素‘1’删除,列表变为:

a4e7b79e0d61f65e92cc9fb6b76fea66.png

第二次执行到data.remove(i)时i为第二个元素,即‘3’,此时将‘3’删除,列表变为:

2b9f54b13b8bf1b1c3e87f3d0c7cbcff.png

此时列表已经没有第三个元素了,即退出循环,将[2]返回。

所以尽量不要在循环中用remove删除元素,如果确有必要,可以逆向删除

4)py文件命名:随意归随意,别和模块名撞车。

今天来了兴致,要学一下turtle库,于是立马创建了个文件turtle.py,先跑一个五角星的案例再说,现成的代码,问题不大:

26582a37e60d10e37a4b39b455e078e8.png

就在你脑子里还在纠结,一会要用turtle画个金刚葫芦娃,还是做个飞机大战游戏的时候,你接下来的半小时陷入了一个百度很难解决的错误:

67e7ee86ec5e4ef8e2cb5d5fee028458.png

What?turtle没画笔属性?怎么可能?没错啊!

其实这个就是因为你这个文件本身就叫turtle,你import,没import进来官方库,把自己这个文件又引入了一遍,所以你当然没实现pensize了……

所以,py文件命名,别用模块名!同理,变量名别用成关键字。

5)sort和sorted:听说不用重复造轮子了?调用现成的排序需写准。

Python自带了排序函数?快来试一下。

test=[8,7,5,6,3,1,2]sorted(test)print(test)

这样的结果是根本没有排序?函数问题吗?非也。

test=[8,7,5,6,3,1,2]test=sorted(test)print(test)

这样就没有问题,由此可见,sorted排序并没有真正的把test给更改了,而是返回了一个排好序的数组。都怪一些书的分类,老是强调列表是可变变量,就总以为任何时候它都会被直接修改……

其实仔细想想,不破坏原有数据,才是真正的负责任的函数啊。

不过这个问题,也可以直接用列表的sort方法:

test=[8,7,5,6,3,1,2]test.sort()print(test)

看来,所谓的列表可变,通常是自己的方法才变的畅通啊。外部的修改,目前来看,还真很少有直接把列表给动了的,多是新搞一个……

这个问题其实,不光是排序本身。字符串replace掉一部分,不赋值出去,原来的字符串并没改。图片处理中,图片上合成了新元素,不赋值出去,原图片不变。

总之,变量修改后如果改的不是本身,要记得赋值再用就对了。

6)全局变量:函数里用到和外面同名的变量,它俩可以有关也可以无关。

默认函数内的变量作用域仅仅是函数内:

count=0def add():    count=count+1    add()print(count)

这样是会报错的,除非在函数里申明一下,count是全局变量:

count=0def add():    global count    count=count+1for i in range(5):        add()print(count)

这样,就可以输出结果为5啦,设置“公共变量”有些时候还是有用的。记得写一个global就好,计数神马的都可能用到。

7)文件读写:听说py文件适合用utf-8编码,那就utf-8一统天下?

现在很多Py开发工具,会默认给我们创建utf-8格式的py文件。所以你会发现现在写程序很多时候不用再开头加上一句:

#coding=utf-8  或者:# -*- coding: UTF-8 -*-

直接开始正式编码就好,简单粗暴。

不过也正是由于这一点。读取文件时也就有了个坑,就是编码问题。

不知道你们注意了没,最新版本的Win10系统,默认建立记事本也是utf-8的,而不是原来的ansi。

科普一下ansi:

其实ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码。你的美国同事Bob的系统中ANSI编码其实是ASCII编码,而你的系统中(“汉字”正常显示)ANSI编码其实是GBK编码,也就是Windows默认的汉字编码。

所以如果是Win10默认创建的utf-8编码的记事本:

391db1c75370eea04f269fd496c10698.png

with open("log.txt",'r') as f:    notices=f.readlines()    for notice in notices:        if notice.split(" ")[0]=="故障":            print(notice)

这个按照我们预想的结果,应该会打印故障信息,结果是啥也不显示。

为啥呢?别急,加句print看一下notices:

c31bb008e22a83d535eec185a1d0dfcd.png

原来如此,默认在windows下执行,是按GBK去读的,结果现在的记事本是utf-8啊。Windows改成默认utf-8建立文件本来是个好事,那我们读取的时候还是指定一下编码吧:

with open("log.txt",'r',encoding='utf-8') as f:    notices=f.readlines()    for notice in notices:        if notice.split(" ")[0]=="故障":            print(notice)

于是就正常啦。

但是如果是win7系统,默认记事本是ansi的,那就不用多此一举的指定编码了,因为默认就是按GBK读取。

8)文件路径:别忘了转义字符,该取消转义的时候要记得

这个其实如果养成习惯,在路径字符串前加个r取消转义,问题不大。但是,既然踩坑的,多数是新手阶段,还是要提醒一下的:

from PIL import Imageimg=Image.open('c:\Users\Pansk\project\web_ddt.jpg')

比如上面这个读取图片的代码,就一定会报错:

SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: tr

这个报错,如果你去百度,只会告诉你和unicode有关的东西。因为,\u在转义字符效果里,就是代表后面四位是unicode字符。这里明显只是个路径,是个路径,路径……

所以你可以这样来写绝对路径:

from PIL import Imageimg=Image.open('c:\\Users\\Pansk\\project\\web_ddt.jpg')

当然,就不如这样:

from PIL import Imageimg=Image.open(r'c:\Users\Pansk\project\web_ddt.jpg')

相对路径,用到的是/,还好不用特殊处理,记得默认相对的是代码所做文件夹就好。

9)导入模块:import 与from import还是要区分一下的。

这个之前我有篇文章是区分了一下,包和模块的概念的。大家可去了解一下,链接:

https://mp.weixin.qq.com/s__biz=MzU2NjQ5NzAwNw==&mid=2247483884&idx=1&sn=32f1f798886b0c89629d85b1adf104a4&chksm=fcaada6ccbdd537aa003a4bfa92639528d96bac9dbdaa7c120af102547695b6e8270b1c085c0&token=219477806&lang=zh_CN#rd

这里其实也不算是坑吧,是一种书写习惯的问题。

考虑一个场景,你要引入一个模块当中的一个子模块或函数:

from PIL import Imageimg=Image.open("test.png")

这样from import就挺好,但是如果用到的子模块或函数特别多:

from turtle import *color('red', 'yellow')begin_fill()hideturtle()speed(10)while True:    forward(200)    right(144)    if abs(pos()) < 1:        breakend_fill()done()

这程序是没问题的,也是画五角星,但是尽量还是不要import * ,一方面因为这样引入的东西太多,会减慢程序速度。不过还好,对咱们来说可以忽略。但是感觉程序的可读性就降低了。

初学者,看这代码,就不知道某个关键字或者函数,到底是Python里面自带的,还是你引用那个库里的。而且万一俩库里有重名的函数,就混了。

比如math模块中有pow,Python内置也有。

60d206c1a3884bb1d04e51d45074c284.png

所以我个人觉得,更推荐:

import turtle as t

然后在下面用到海龟库的时候,前面来一个t.,是不是更清楚一点呢?

10)安装第三方库:这个还是有些注意的地方。

a) 安装模块名和引入名可能不一致。

比如引入的PIL库,在安装的时候叫pillow。引入的cv2模块,在安装时叫opencv-python。

b) pip下载速度过于慢,频繁报网络错误。

这个没啥说的,切换国内源下载就好。

临时命令:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ requests

永久改变:

在用户的根目录下创建 .pip 文件夹,新建 pip.conf 文件,在文件中写入要使用的镜像:

[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = https://pypi.tuna.tsinghua.edu.cn

c) 还有一些库要区分32位还是64位系统以及对应特定Python版本。

这种需要手动去某些网站下载whl文件,然后用pip本地安装。

好了,以上就是我要分享的Python学习之中的一些坑。可能我遇到的还不够全面,所以有凑数的嫌疑哈。我们发现,有些确实是语言的坑,有些是我们的理解不够深入。话说回来,有一些东西,倒也不必深究理解,就像Python中a,b=b,a的交换原理。

总之一句话,实践出真知。多实验,多思考,思考不出来就去网上查阅一下就好。毕竟多数人用语言,仅仅是个工具,留着我们更多的精力在算法逻辑上要更靠谱一点。

学习Python中,你有遇到哪些“坑”,如果出坑的?欢迎交流。

f9e6f1830d9fd2f015403b5adaaf4fa3.png

8c6a8c49eb63d8f453694683342fe0ce.gif 如果你觉得有用,可以点个在看
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值