zoukankan      html  css  js  c++  java
  • Effective Python

    这本书看什么?

    能收获什么,作者的python经验,语言语法经验,语言实用技巧。还有作者想给我们推荐的一种编码思想,就是pythonic,这个东西是什么呢?我目前的理解就是用python的语法糖去简化代码逻辑,最终达到简单不简陋。

    整理自己觉得有用的技巧,但是不会按照他的点来排序。

    ASCII码

    基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言

    Unicode字符

    一种世界通用的编码方式,存任意字符,包括中文,拉丁字母。转为二进制的话必须用encode,解码decode。

    Utf-8

    UTF-8是针对Unicode的一种可变长度字符编码;它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部份修改后,便可继续使用。

    怎么理解呢?

    ASCII 是简单的解码拉丁字母,但是随着开发应用,中文或者其他语言的加入,这肯定不够,所以开发了UNicode编码来使用,这个编码是全世界的语言都包含了,但是字节数比较多,所以如果你全部用unicode 的话,那么可能容量会变大。所以utf-8是一个变长的编码,如果是拉丁字母就用ascii的长度去解,如果是中文,就用unicode的编码解。这样的话,尽量是减少了内存的冗余。

    1.Pythonic的思考方式

    崇尚直观,简洁又易读,简单不简陋。

    python 的版本注意

    注意2.0跟3.0的一些语法区别,如果你的代码里面有两个语法规则,很容易出错。
    案例:做过的项目里面,旧的包体还是用2.5的版本,但是最新的是2.7的版本,所以如果程序开发的时候用了2.7的语法那2.5的包体就不行了。所以尽量还是统一你的版本。

    首先我们写的语法应该遵照pep8,pylint语法规则

    这里我的理解是一个项目组应该有尽量统一的编码规范,除了规范正确的语法,也方便沟通和交流。

    多辅助函数来取代复杂的表达式,应该多拆分函数处理

    1.字典获取的值的时候,使用内置get函数加上默认参数简化if
    案例:
    num = dicNum.get("Num", 0) 如果dicNum里面没有"Num" 那么就会默认返回0,如果不填0 的话,返回的是None,推荐还是填写。

    2.不要过度使用语法糖去简化表达式
    比如利用空字符串 空列表 0都会判断为False, 因此可以简化if条件
    案例:
    isShow = lstTemp or false
    当lstTemp是空列表那么就会返回or 右边的值
    但是这样阅读性其实比较差,执行需要条件。
    所以加入了这样的写法来替代:
    isShow = lstTemp if lstTemp else false
    我目前认为简单的语句可以使用,即if和esle里面的条件比较单一可以这样做。
    书里推荐的方式是,新写一个函数去替代重复的if else,而不是过度的简化每一句if else。

    序列技巧

    sName[3:len*(sName)] ==> sName[3:0]
    sName[0:3] ==> sName[:3]
    用负数表示倒着数的位置,比如-1就是倒过来数的下标1 即倒数第二个
    sName[3:-1]
    

    序列在切割时候可以越界切割(即你的序列长度只有10,但是你可以[:20]也能返回正确的答案),不会出现异常,但是越界访问还是会报错的。
    切割之后会产生新的序列(因为序列是值引用,比如字符串)

    sName[:] 拷贝一份
    

    序列切片可以使用步进的方式

    [::n] 从每n个元素里面取1个出来
    

    翻转字符串
    [::-1] 对于字节串ASCII串有效果,不过对于Utf-8编码的不行
    w = "谢谢"
    x = w.encode("utf-8")
    y = x[::-1]
    z = y.decode("utf-8") // 会报错,已经错乱了

    用列表制作另一份列表的技巧 ,列表推导式

    使用列表推导式

    slst = [x**2 for x in lstA if x % 2 == 0]
    

    建议:不要使用两个推导式组合,不好理解,阅读性太差,而且很长

    使用迭代器来改写数据量大的列表推导式,而且可以进行组合:

    it = (len(x)  for x in open("temp/myfile.txt"))// it是一个迭代器,很类似一个列表指针,但是单向一次性的,只能一个个往下遍历,不能后退、跳
    print(next(it))
    print(next(it))
    

    组合:
    roots = ((x,x**0.5) for x in it) // it ,roots都是迭代器,这样组合起来也看起来简单一些了,不会很长。

    用enumerate 替代range enumerate(lstname,1)

    为什么?
    案例:

    for i in range(lstTemp):
    	print(i, lstTemp[i])
    	
    ==>
    for i, item in enumerate(lstTemp)
    	print( i,item)
    

    更加简洁而且容易理解,你是想要索引下标,而且2.7以上可以指定下标开始的数字enumrate(lsttemp, 1)

    zip 函数同时遍历两个迭代器 for name, num in zip(lstname, lstnum)

    案例:

    lstnames = ["lisa", "xiaoming", "xiaohong"]
    lstnums = [len(name) for name in lstnames]
    for idx, name in enumerate(lstnums):
    	dName[name] = lstnums[idx]
    

    你获取了名字和长度的字典数据,上面的做法实际上是遍历了两个列表, 你要选择一个进行遍历。可读性不是最优的

    ==>
    for name, num in zip(lstnames, lstnums):
    	dName[name] = num
    

    是不是相当于两个列表是同等地位的,也很容易看出来
    但是如果俩个列表不等长,会终端循环,所以推荐是一定是两个列表同等长度的时候使用

    不要在for,while循环外边使用else

    这个我不是很认同,我觉得是可以使用的,作者觉得可读性太差, 新人很容易误解,但是文中提到一个解决方案是写辅助函数帮忙处理可能更好。

    try/except/else/finally

    try 写可能有异常的代码,else 没有异常执行的代码(减少try的代码量,逻辑的拆分),finally 有异常返回异常并且处理一些事情(关闭文件打开等问题)

    2.函数

    函数位置参数

    1.采用可变参数*args
    2.指定参数 ishow = 1
    3.函数默认参数不要用{},[] 因为在编译的过程中就已经执行了默认参数的执行,都是引用对项目,很容易被改变

    3.类于继承

    推荐辅助类的使用, 函数嵌套函数尽量避免,使用类替代

    @classmethod 类函数用于多态,多个类一样的操作,可以使用类方法去多态

    因为:

    @classmethod
    def generate_inputs(cls, config):
    	...返回类相关cls 类似__init__的构造器,返回类的对象
    

    使用:
    1.作为构造函数的补充
    2.作为普通函数的补充,不需要实例就能执行的函数
    3.可以作为工厂方法的结构
    4.在创建实例前做一些处理

    mix-in 是一种小型的组件类,它只是定义了其他类可能需要提供的一套附加方法,而不定义自己的实例属性。通过继承实现。

    Mixin 只用于拓展子类的功能,不能影响子类的主要功能,子类也不能依赖 Mixin
    像是扩展方法的一种,不改变原来的类,而给类增加新的功能,可以通过继承处理。
    一个mixin一般只有一类功能,方便组合,可以继承多个mixin类实现多个功能。
    可以结合定制函数的方式,getitem setitem 的方式去简化
    跟基类功能的区别是什么?有无主需求一样实现

    super 作为多重继承,父类的区分,supre(父类,self).add

      class FooChild(FooParent):
          def __init__(self):
              //super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类 FooChild 的对象转换为类 FooParent 的对象
              super(FooChild,self).__init__()  
      单继承的时候项目用的更多是 FooParent.__init__() 跟super没有区别的,但是多继承的时候,
      使用了super一个节点只会调用一次,没有使用,基类的节点多一个子类就会多执行一次,效率很差
    

    私有变量的方式

    两个下划线的是私有__name,所以我们自己定义自己的私有形式,而不去使用python的私有变量命名方式。实际上是变换了私有属性的名字来,比如你命名为__Name, 事件上生成对象后会有一个__XXX__Name 的属性。就是说实际上存在,但是改了名字,你直接用不了而已。但是你可以根据名字找到那个变量,就一样可以用。为什么做成这样呢?因为py是一个开放的语言,不想太限制

    定制函数

    __getitem__ 可以跟列表一样lsttemp[index] 访问下标
    
    def __getitem__(self, index):
    	return self.__dict__.get(key) // 通过__dict__获取对象的属性
    	
    __len__ 实现接受len()
    
    def __len__(self):
    	reurn xx
    
    __repr__  用于print()的参数
    
    def __repr__(self):
    	return 
    

    容器类型可以继承 collections.abc import Sequence 抽象基类,提醒你实现上面的一些容器相关的接口。这样做比较统一安全

    class BetterNode(Sequence)
    	__len
    

    但是如果你的容器比较简单那么建议直接继承字典或者列表,dict,list

    4.元类及属性

    不需要用get set属性

    直接使用xx.xxx 更符合python的风格
    如果需要,@Property

    6.内置工具

    双向队列 deque
    有序字典 OrderDict
    默认字典 defaultdict
    堆队列 heappush(A,5)
    二分插值 bisect_left(lst, idx)
    decimal 精确小数
    pip工具

  • 相关阅读:
    把一个数组 赋值给一个新数组
    上传图片时进行压缩
    input上传文件 显示进度条
    vue 后台接口返回文件流地址的下载
    时间戳转换
    JS 两个含有部分相同属性的对象如何快速给对应的key赋值
    javascript中把一个数组的内容全部赋值给另外一个数组
    微信小程序wxs如何使用
    优化内存
    解决position:fiexd相对父元素定位
  • 原文地址:https://www.cnblogs.com/leilei-weapon/p/14381422.html
Copyright © 2011-2022 走看看