前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Effictive python学习总结连载(1)

Effictive python学习总结连载(1)

原创
作者头像
J_J
发布2018-10-01 22:51:38
6010
发布2018-10-01 22:51:38
举报
文章被收录于专栏:每周一脱topic每周一脱topic

python从读研开始就在用了,拿来做过web后台、安全分析、爬虫、测试框架等等,挺强大的。最近借放假和看书和整理的机会,系统的总结下。主要是2方面:一个是书或资料中学到的核心点,咀嚼过后自己来总结;一个是自己思考的东西。

这里看的书是《Effective Python-编写高质量Python代码的59个有效方法》,这本书还不错,作者应该写过不少python。网上有翻译版本,但不知道是否有版权,gitbook链接

接下来就按照书的章节划分,总结要点,并写写自己的一些思考。

一、Pythonic?Thinking-用python的思维去编码

1.尽量用3.X高版本的python

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了,这是大势所趋。

2.遵循PEP8代码风格规范

PEP 8提案

PEP8提案规定了规定了很多的编码规范,这个一定要看,并尽量遵守。之前看很多人写python命名函数等还是用java的驼峰写法,这并不Pythonic。风格一致更有利于维护。这个有很多相关翻译文章了,这里不阐述。

几个大家容易忽略的:

  • import尽量一行一个。先是内置模块,再是第三方模块,再是内部模块。
  • class用驼峰,函数、变量都用小写加下划线。
  • 用好ide的格式化代码功能,每次保存前格式化代码一下。

3.python2编码问题

几乎每个使用python2的人应该都遇到过编码问题,在读写网页、操作文件的时候,不小心就报编码不对的error。然后各种ASCII、Unicode、str、utf-8概念混在一起后,这里也比较使人混乱。这里总结下,把这个问题说明白。

3.1 为什么会存在字符编码这种东西?

大家都知道我们的所有信息在硬盘里其实都是01这样的数字,电脑怎么知道这些01数字代表哪个字符啊?这里的解决方案和计算机原理是一样的。就是人为规定一个表,规定好很多01组合,分别对应一个唯一的字符。

3.2 几种重要的编码

有3个主要的编码,需要搞明白,其实就是一个key-value的对应表。

  • ASCII

美国人最开始搞出计算机,制定了一套字符编码的标准叫ASCII(American Standard Code for Information Interchange)。它把大、小写26个字母、常用标点等都唯一对应一个数。例如大写字母A,对应01000001。标准ASCII码最高位没用,7位最多能表示128个字符。那个时候pc和网络都很菜鸡,这个表已经够用了。

  • GBK

随着计算机进入中国,中国字怎么编码呢?同样的,中国国家标准总局设计了一套编码叫GB2312,又称GB0,它基本覆盖了常见的中国字。后来,在此基础上覆盖了更多生僻字、少数民族字体等,称为GBK。

  • Unicode

由于这个世界上存在很多种文字,其它的文字又该怎么办呢?于是统一联盟国际组织提出了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中定义的字符。

3.3 python2中的坑

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字节编码。

代码语言:javascript
复制
>>> 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等等,但切忌混合使用容易出错。

4. 使用辅助函数替换复杂表达式

意思就是如果逻辑复杂不要糅杂在一起,不清晰,可以将其抽象为函数调用来解决。

这里我觉得更有意义的是要有一个意识:写代码是给别人看的,顺带着实现功能。工作中也接触到一些同事的代码,通篇零星注释或者根本没有注释,要花好多时间去猜代码的意思,代码结构也冗杂。所以这里要重点注意的是可维护性、注释清晰,方便后期的维护升级。尽量少留坑给后人。

5. 切片操作的底层

切片不指定开始、结束,会浅复制一份,对复制后的操作不会影响之前的。但是要注意是不可变类型。如果是list等可变类型就不是了。

代码语言:python
复制
>>> 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个不要同时指定。

代码语言:python
复制
>>> a = ['a', 'b','c','d','e','f']
>>> a[::2]
['a', 'c', 'e']

7. 使用列表推导

生成list、dict等的时候,可以采用列表推导的方式,这样更简洁、高效。

代码语言:python
复制
>>> a = ['a', 'b','c','d','e','f']
>>> b = [each for each in a if each not in ('a', 'c')]
>>> b
['b', 'd', 'e', 'f']

8. 列表推导中不适用超过2个表达式

这里的意思列表推导中超过2个for,就比较难看懂了,不推荐,然后使用2个传统的for循环进行替代。

注意:用下面代码测了简单测试了下性能,列表推导来生成列表,相对于传统的for循环加append,速度上列表推导快3-4倍。所以我觉得应该是尽量用列表推导的方式来生成,但格式和注释要跟上,抵消逻辑复杂的影响。

代码语言:python
复制
# 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。

9. 用生成器表达式替换数据量较大的列表推导

列表推导会把数据全部加载到内存,当数据过大时会有问题。这时候要使用生成器表达式,这时并不会把整个序列计算出来,而是会返回一个iterator,每次使用next来拿下一个。

生成器表达式:使用列表推导的地方,外面变为括号即可。

10.使用enumerate来替换range

这个是常规用法,不多说。

11.zip的使用

2个数组的元素对应的拼接处理。常规用法。

12.不要在for和while后面写else

for和while的else,当有break跳出时不执行,否则执行。很绕,不熟悉的人可能会产生混淆。所以从可维护性等角度考虑,不要这样写。

13. 利用好try/except/else/finally

2个点注意下就好。

  • finally

不管怎么样都会执行的语句,常用于不管是否异常,需要关闭文件流等。

  • else

try语句块里没有发生异常,那么会执行else中的语句。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Pythonic?Thinking-用python的思维去编码
    • 1.尽量用3.X高版本的python
      • 2.遵循PEP8代码风格规范
        • 3.python2编码问题
          • 3.1 为什么会存在字符编码这种东西?
          • 3.2 几种重要的编码
          • 3.3 python2中的坑
        • 4. 使用辅助函数替换复杂表达式
          • 5. 切片操作的底层
            • 7. 使用列表推导
              • 8. 列表推导中不适用超过2个表达式
                • 9. 用生成器表达式替换数据量较大的列表推导
                  • 10.使用enumerate来替换range
                    • 11.zip的使用
                      • 12.不要在for和while后面写else
                        • 13. 利用好try/except/else/finally
                        相关产品与服务
                        Elasticsearch Service
                        腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                        http://www.vxiaotou.com