python从读研开始就在用了,拿来做过web后台、安全分析、爬虫、测试框架等等,挺强大的。最近借放假和看书和整理的机会,系统的总结下。主要是2方面:一个是书或资料中学到的核心点,咀嚼过后自己来总结;一个是自己思考的东西。
这里看的书是《Effective Python-编写高质量Python代码的59个有效方法》,这本书还不错,作者应该写过不少python。网上有翻译版本,但不知道是否有版权,gitbook链接
接下来就按照书的章节划分,总结要点,并写写自己的一些思考。
python主要分为2个版本:2.x和3.x。这里比较坑的是,2和3之间不兼容,很多2.x版本的代码需要重写才能在3.x跑。当然会有一些自动转换工具和库使用,这里不阐述。
当前2.X最新版本为2.7.15,2.X版本的应用比较广泛,很多老的工具和库都是基于2.x版本写的,所以用到一些老旧的、未提供3.x版本支持的库时,只能选择2.x版本的python。这里要注意的是,2.x版本功能不再更新了,只修bug,核心团队表示在2020年会停止维护。这里有个倒计时的网站:https://pythonclock.org
3.x最新版本为3.7.0,除非特殊的原因,我们应选择3.x版本的python。不管是性能、安全性、各种新功能都只将在3.x版本中可用。而且基本上常用的库都已经迁移3了,这是大势所趋。
PEP8提案规定了规定了很多的编码规范,这个一定要看,并尽量遵守。之前看很多人写python命名函数等还是用java的驼峰写法,这并不Pythonic。风格一致更有利于维护。这个有很多相关翻译文章了,这里不阐述。
几个大家容易忽略的:
几乎每个使用python2的人应该都遇到过编码问题,在读写网页、操作文件的时候,不小心就报编码不对的error。然后各种ASCII、Unicode、str、utf-8概念混在一起后,这里也比较使人混乱。这里总结下,把这个问题说明白。
大家都知道我们的所有信息在硬盘里其实都是01这样的数字,电脑怎么知道这些01数字代表哪个字符啊?这里的解决方案和计算机原理是一样的。就是人为规定一个表,规定好很多01组合,分别对应一个唯一的字符。
有3个主要的编码,需要搞明白,其实就是一个key-value的对应表。
美国人最开始搞出计算机,制定了一套字符编码的标准叫ASCII(American Standard Code for Information Interchange)。它把大、小写26个字母、常用标点等都唯一对应一个数。例如大写字母A,对应01000001。标准ASCII码最高位没用,7位最多能表示128个字符。那个时候pc和网络都很菜鸡,这个表已经够用了。
随着计算机进入中国,中国字怎么编码呢?同样的,中国国家标准总局设计了一套编码叫GB2312,又称GB0,它基本覆盖了常见的中国字。后来,在此基础上覆盖了更多生僻字、少数民族字体等,称为GBK。
由于这个世界上存在很多种文字,其它的文字又该怎么办呢?于是统一联盟国际组织提出了Unicode编码。它统一对各种文字进行支持,大家都能使用。Unicode有两种格式:UCS-2和UCS-4,分别用2个字节和4个字节。2的32次方这个量级,理论上可以把全世界的文字进行唯一标识了。
像Java、python3等语言,内部字符都是采用Unicode来编码的。
Unicode编码只是定义了一个表,某个01串代表某个字符,但是怎么在网络传输、在磁盘上保存没有硬性限制。由于网络带宽和磁盘是有限的,大家就开始进行了一些优化,希望用更少的字符来传输、保存unicode字符。这时候常见的UTF-8、UTF-16等登场了,我们以使用最多的UTF-8来举例。
UTF-8是一种可变长度的编码格式,使用1-4个字节来表示对应的Unicode字符。例如,对于UTF-8编码中的任意字符S,如果S的第一位为0,则S独立的表示一个字符(ASCII码)。这样就只需要1个字节,来对应原先的4字节Unicode字符。这样说就清晰了,UTF-8、UTF-32等等,都是Unicode的一种表示方式,如同指针一样,但是它们真正指向的还是Unicode中定义的字符。
python在91年被设计出来,并没有考虑太多编码格式的问题,所以python默认的编码是ASCII。因此不在py文件的第一行声明utf-8编码,那么代码中含有中文等非ASCII字符时,就会产生语法错误提示存在非ASCII字符。
python中保存字符有2种类型:str和unicode。我们从下方可以看到,这里s_2直接赋值类型是str,s_3加上u再赋值就是unicode类型。再看内部表示,s_2是utf-8的编码(跟操作系统有关),而s_3是unicode4字节编码。
>>> s_2 = '你好'
>>> s_3 = u'你好'
>>> type(s_2)
<type 'str'>
>>> type(s_3)
<type 'unicode'>
>>> s_2
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> s_3
u'\u4f60\u597d'
这个时候大家是否回忆起这样的经历:在mac或者pycharm内运行的py脚本各种中文显示正常,但是在Windows的cmd中执行的时候却打印的是乱码呢?这就是因为cmd命令行中的字符编码是gbk的,而py中输出的却是utf-8或unicode编码字符。
python中从str转换为unicode使用解码decode函数,而从unicode转换为其它编码使用编码encode函数。
原则:我们在py内部使用的字符格式都要转换为unicode类型,而输出和读取外部结构时(数据库、文件、web等)全部统一使用某一种编码,可以是utf-8、gbk、utf-16等等,但切忌混合使用容易出错。
意思就是如果逻辑复杂不要糅杂在一起,不清晰,可以将其抽象为函数调用来解决。
这里我觉得更有意义的是要有一个意识:写代码是给别人看的,顺带着实现功能。工作中也接触到一些同事的代码,通篇零星注释或者根本没有注释,要花好多时间去猜代码的意思,代码结构也冗杂。所以这里要重点注意的是可维护性、注释清晰,方便后期的维护升级。尽量少留坑给后人。
切片不指定开始、结束,会浅复制一份,对复制后的操作不会影响之前的。但是要注意是不可变类型。如果是list等可变类型就不是了。
>>> a = [1,2,3,4]
>>> b = a[:]
>>> b
[1, 2, 3, 4]
>>> a
[1, 2, 3, 4]
>>> b[0] = 1000
>>> b
[1000, 2, 3, 4]
>>> a
[1, 2, 3, 4]
切片除了指定开始、结束,还可以设置选择的步长。3个不要同时指定。
>>> a = ['a', 'b','c','d','e','f']
>>> a[::2]
['a', 'c', 'e']
生成list、dict等的时候,可以采用列表推导的方式,这样更简洁、高效。
>>> a = ['a', 'b','c','d','e','f']
>>> b = [each for each in a if each not in ('a', 'c')]
>>> b
['b', 'd', 'e', 'f']
这里的意思列表推导中超过2个for,就比较难看懂了,不推荐,然后使用2个传统的for循环进行替代。
注意:用下面代码测了简单测试了下性能,列表推导来生成列表,相对于传统的for循环加append,速度上列表推导快3-4倍。所以我觉得应该是尽量用列表推导的方式来生成,但格式和注释要跟上,抵消逻辑复杂的影响。
# coding: utf-8
import cProfile
import random
a = [[[random.randint(0, 100) for i in range(100)]] for i in range(100)]
def test():
"""
使用列表推导来创建
:return:
"""
for m in range(100000):
c = [temp for each_a in a for temp in each_a]
return c
def test2():
"""
使用for循环的方式来创建
:return:
"""
for m in range(100000):
c = []
for each in a:
for temp in each:
c.append(temp)
return c
cProfile.run('test()')
cProfile.run('test2()')
test大概0.887秒,test2大概3.089秒。2.9 GHz Intel Core i5、8 GB 2133 MHz LPDDR3、macbook pro。
列表推导会把数据全部加载到内存,当数据过大时会有问题。这时候要使用生成器表达式,这时并不会把整个序列计算出来,而是会返回一个iterator,每次使用next来拿下一个。
生成器表达式:使用列表推导的地方,外面变为括号即可。
这个是常规用法,不多说。
2个数组的元素对应的拼接处理。常规用法。
for和while的else,当有break跳出时不执行,否则执行。很绕,不熟悉的人可能会产生混淆。所以从可维护性等角度考虑,不要这样写。
2个点注意下就好。
不管怎么样都会执行的语句,常用于不管是否异常,需要关闭文件流等。
try语句块里没有发生异常,那么会执行else中的语句。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。