10天读完《编写高质量代码 改善Python编程的91个建议》——Day4

计划

Hello,这是一个读书摘要的计划,10天读完《编写高质量代码 改善Python编程的91个建议》,我会每天摘录大概9个书中提到的建议,分享在这里,也作为自己的打卡任务。关于这本书,他并不是python入门的教学书籍,而是一本用来改善编程习惯和风格的书,可以帮助我们写出漂亮的,也就是符合pythonic的python代码。书中的知识难度不会很大,每天看几条,然后落实到实际编程中加以巩固,就能融会贯通,久而久之也就能养成好的编程习惯。如果你没有时间看原书,那么直接看我的摘要就好啦,遇到感兴趣的再去详细了解也会方便很多,当然这里摘要的内容是我觉得有用的部分啦。注意,一定要会运用!

书摘

建议29 区别对待可变对象和不可变对象

  1. 不可变对象有:数字,字符串,元组
    可变对象有:列表,字节数组

  2. 可变对象作为函数默认参数时可能变成不可变(内存中同一个地址),解决办法是传入None作为默认参数
    例如:

# 错误
def fn(arg=[]):
    """"""

# 正确
def fn(arg=None):
    if arg == None:
        arg = []

建议30 [] () {} 一致的容器初始化形式

  1. 列表解析

a)语法:[expr for iter_item in iterable if cond_expr]

b)支持多重嵌套

c)支持多重迭代
例如,求['a', '1', 1, 2] 和 ['1', 3, 4, 'b'] 的笛卡尔积

l1 = ['a', '1', 1, 2]
l2 = ['a', '1', 1, 2]
[(x,y) for x in l1 for y in l2 if x != y]

d)解析中的表达式可以是简单表达式,也可以是复杂表达式,甚至是函数

e)解析中的iterable可以是任意可迭代对象
例如,

f = open('test.txt','r')
res = [i for i in f if 'abc' in i]
print res
  1. 元组,集合,字典也有类似的解析语法

元组:(expr for iter_item in iterable if cond_expr)
集合:{expr for iter_item in iterable if cond_expr}
字典:{expr1,expr2 for iter_item in iterable if cond_dir}

  1. 注意,在元组中,(1)与(1,)是完全不同的,后者才是元组

建议31 记住函数传参既不是传值也不是传引用

  1. python与C/C++的赋值原理不一样

同样一段代码

a = 5
b = a
b = 7

在C/C++中,『a=5』表示从内存中申请一块内存并将a的值5复制到该内存中,『b=a』表示b申请一块内存,然后把a的值复制到b的内存,『b=7』表示把b内容中的值改为7。

在Python中,『a=5』表示内存中存一个数值5,然后a指向这个内存,『b=a』表示b也指向该内存,『b=7』表示内存中存一个数值7并把b指向这个内存。下面验证一下,

a = 5
id(a)
b = a
id(b)
b = 7
id(b)
id(a)
  1. Python传的是对象或者说是传对象的引用

函数参数在传递的过程中将整个对象传入,对可变对象的修改在函数外部以及内部都可见,调用者和被调用者之间共享这个对象,而对于不可变对象,由于不能真正地修改,因此修改往往是通过生成一个新对象然后赋值来实现的。

建议32 警惕默认参数潜在的问题

  1. 默认参数是共享的,例如
def fn(num, data=[]):
    data.append(num)
    return data

fn(1)
# [1]
fn(2)
# [1,2] 而不是 [1]
  1. 不想共享?使用None作为占位符
def fn(num, data=None):
    if data is None:
        data = []
    data.append(num)
    return data

建议33 慎用变长参数

  1. 可变长度参数,使用*arg和**kwargs

a)*arg 用于接受一个『元组』形式的参数列表来传递非关键字参数,个数任意
b)**kwargs 用于接受一个『字典』形式的关键字参数

  1. 为什么要慎用?

a)使用过于灵活,他人阅读比较花时间
b)如果一个函数参数列表过长,通常意味着该函数可以有更好的实现方式,应该被重构
c)适合下列情况使用:
i)为函数添加一个装饰器
ii)参数数目不确定
iii)用来实现函数的多态,或者在继承情况下子类需要调用父类的某些方法

建议34 深入理解str()和repr()的区别

  1. 两者多数情况下相同,区别大致有以下几点:
    a)str()主要面向用户,目的是可读性;repr()面向python解释器,目的是准确性(debug用)
    b)解释器中直接输入a时默认调用repr(),而print a时则为str()
    c)repr()的返回值一般可以用eval()函数来还原对象,如 obj=eval(repr(obj))

建议35 分清 staticmethod 和 classmethod 的适用场景

  1. Python中静态方法staticmethod,类方法classmethod都依赖于装饰器来实现,如
@staticmethod
def fn1(arg): return

@classmethod
def fn2(arg): return
  1. 类方法可用在继承中(父类中使用)

建议36 掌握字符串的基本使用

  1. 小技巧

Python遇到未闭合的小括号时会自动将多行代码拼接为一行,并把相邻两个字符串字面量拼接在一起(取出换行符和前导空格),例如

s = ('SELECT * '
        ' FROM person '
        ' WHERE gender="male" ')
print s
  1. Python2 中判断变量s是不是字符串应该使用 isinstance(s, basestring) 注意不是str,因为basestring分为str和unicode

  2. 字符串基本用法掌握

a)性质判断:isalnum(), isalpha(), isdigit(), islower(), isupper(), isspace(), istitle(), startswith(), endswith() ...

b)查找与替换:count(), find(), index(), rfind(), rindex(), replace(old, new [, count]) ...,这些都支持start,end参数,注意要判断是不是子字符串应该使用in,not in

c)分切与连接:partition(sep), rpartition(sep), splitlines(), split(), rsplit() ...,注意split()与split('')返回值不同

d)变形:lower(), upper(), capitalize(), swapcase(), title(), String.capwords(), strip(), lstrip(), rstrip() ...

建议37 按需求选择sort() 和 sorted()

  1. sorted 使用更为广泛,两者形式:

sorted(iterable[, cmp[, key[, reverse]]])
s.sort([cmp[, key[, reverse]]])

注意,cmp是用户定义的比较函数(不常用),reverse表反转(默认从小到大)

  1. sorted作用于任务可迭代对象,sort用于列表

  2. sorted返回一个排序完的新表,sort直接修改原列表

  3. sorted 可针对不同数据结构排序,如字典

score = {'Alice':100, 'Bob':87, 'Cat':95}
sorted(score.items(), key = lambda item:item[1])
print score
posted @ 2020-01-21 16:19  MrDoghead  阅读(174)  评论(0编辑  收藏  举报