你是不是总是觉得学了python好久,蓦然回首,总是感觉写的代码不是那么有pythonic的味道。看看别人的代码(django,webpy),再看看自己的代码,觉得就是一java-python的混合体。鉴于这种问题,我准备要多学习别人的一些技术和方式,这不,在网上看到一本不错的书:[writing idiomatic python ebook] 。告诉怎么写出python风格的代码。本来想共享到网盘的,但是一想,这样不好吧,人家的书是挂在上面付费卖的,也不贵,10刀。所以就不共享了。这里把里面的一些注意点以笔记的形式分享出来一起学习。
ps:我今天发现在163网易阅读里有这本书,提供下链接:http://yuedu.163.com/source/cl_dc23b96c2df84533957ffb1089e90604_4
在if语句中用链式比较使之更简明
x = 5 if x > 1 and x < 6: print 'python'
改成:
if 1 < x < 6: print 'python'
不要在if语句后面直接写代码,而是换行
x = True if x:print 'python' print 'is great!'
改成:
x = True if x: print 'python' print 'is great!'
在条件判断时,应该避免直接和True,False,None进行比较(==)
比如我们判断一个集合为空是,会这样写:
l = [] if l == []: print 'l is empty list'
改成:
l = [] if not l: print 'l is empty list'
其实在if语条的条件判断时,我们一般的语境上下文还是很明确,如对象是否为None,是否条件为True,或者集合是否为空,字典是否为空。python支持直接在if后台跟着这些对象,自动为根据语境转换为相应的布尔值(True或False)。 满足如下的情况,都会认为是False:
但是有些情况还是不同的,不能适用于这个规则。看下面一个实例:
def getCurrentPositon(position=None): if not position: print 'you must set you current position!' getCurrentPositon(0)
方法的作用是得到根据传入的位置做相应的工作。如果传入参数0应该也是合理值,即在坐标原点位置。但是方法还是会打印'you must set you current position!'。 因为0值被条件判断为False。所以应该改成如下 :
def getCurrentPositon(position=None): if position is None: print 'you must set you current position!' getCurrentPositon(0)
显示的比较是否为None,而不依赖内建的布尔转换。注意这里是用 is 操作符没有用 == 比较符。因为None对象在python中是单实例的,而is就是直接比较两个对象是否一样(可以理解占用同一条内存)
用if,else替换三元(ternary)运算操作符
flag = 2 if flag == 1: displayValue = 'man' elif flag == 2: displayValue = 'woman'
改成:
displayValue = 'man' if flag == 1 else 'woman'
用enumerate函数代替for循环中的index变量访问
my_container = ['lily', 'lucy', 'tom'] index = 0 for element in my_container: print '{} {}'.format(index, element) index += 1
改成:
for index, element in enumerate(my_container): print '%d %s' % (index, element)
当for循环体执行完后,可以用else去执行相关的动作
如这样的场景:遍历所有人的年龄信息,决断当前所有人是不是都是成年人,假如以大于等于20岁划分:
all_person_age = [21, 22, 23, 30] is_all_adult = True for age in all_person_age: if age <= 20: is_all_adult = False break if is_all_adult: print 'Tha all are audlt!'
我们这里加了一个 is_all_adult 的标志变量,在循环体中当有年龄小于20岁的人时,把该变量重新置值, 并跳出循环体。我们可以改成 for ... else 的句式,这样可以省略定义一个标志变量:
all_person_age = [21, 22, 23, 32] for age in all_person_age: if age <= 20: break else: print 'Tha all are audlt!'
for...else...的用法就是当for中途退出循环时(没有遍历所有的集合元素)时就不执行else里的语句,反之则执行。
避免用可变的对象(mutable)作为函数参数中的默认初始化值
def function(l = []): l.append(1) return l print function() print function() print function()
将会打印:
[1] [1, 1] [1, 1, 1] [Finished in 0.0s]
这是因为参数的默认初始值只有在定义的时候执行一次,即是单实例的。以后的每一次调用都会用这个对象。改成:
def function(l = None): if l is None: l = [] l.append(1) return l
尽量少定义一些只是用于存储返回值的变量
def all_equal(a, b, c): result = False if a == b == c: result = True return result
改成:
def all_equal(a, b, c): return a == b == c
试着把函数当成对象实例来用,无论是参数传入还是返回值
def print_addition_table(): for x in range(1, 3): for y in range(1, 3): print(str(x + y) + '\n') def print_subtraction_table(): for x in range(1, 3): for y in range(1, 3): print(str(x - y) + '\n') def print_multiplication_table(): for x in range(1, 3): for y in range(1, 3): print(str(x * y) + '\n') def print_division_table(): for x in range(1, 3): for y in range(1, 3): print(str(x / y) + '\n') print_addition_table() print_subtraction_table() print_multiplication_table() print_division_table()
像上面的定义的四个函数,基本结构一样,只是里面进行的运算不同而也(+, -, *, /),我们可以把运算的函数直接作为参数传递进去即可:
import operator as op def print_table(operator): for x in range(1, 3): for y in range(1, 3): print(str(operator(x, y)) + '\n') for operator in (op.add, op.sub, op.mul, op.div): print_table(operator)
在python世界里,一切都是对象,Function也是
多用EAFP,少用LBYL
EAFP:easier to ask forgiveness than permission
LBYL:look before you leap
EAFP可以理解成一切按正常的逻辑编码,不用管可能出现的错误,等出了错误再说;而LBYL就是尽可能每写一行代码,都要提前考虑下当前的前置条件是否成立;
LBYL代码风格:
def getPersonInfo(person): if person == None: print 'person must be not null!' print person.info
EAFP代码风格:
def getPersonInfo(person):
try: print person.info except NameError: print 'person must be not null!'
其实用EAFP风格的代码最大的好处是代码逻辑清晰,而LBYL会导致本来两句话说清楚的事,往往因为穿插了很多条件检查的语句使代码逻辑变得混乱。
不要一根筋似的看到异常就catch并吃掉(swallowing)
如下定义一个方法,请求url并返回响应:
import requests def get_json_response(url): try: r = requests.get(url) return r.json() except: print('Oops, something went wrong!') return None
如果这个函数给第三方调用,万一出了什么问题,用户只会得到一个something went wrong提示,而只能猜出错的原因,是GFW的问题呢,还是url地址格式错误呢。改成如下:
import requests def get_json_response(url): return requests.get(url).json()
把出错的处理权力交给调用方。