Write Idiom Python

Python支持链式比较

# bada=5ifa>1anda<7:pass# goodif1<a<7:pass

Python交换变量

# badx=10y=5tmp=xx=yy=tmp# goodx=10y=5x,y=y,x

Python中替代三目运算符?:

# bada=10b=5ifa>b:c=aelse:c=b# goodc=aifa>belseb

拼接字符列表时,用join方法去实现

# bad

格式化字符时多使用format函数

# badname="tony"age=100str="myname : "+name+" my age : "+str(age)str1="myname :%s my age :%d"%(name,age)# goodstr2="myname :{} my age{}".format(name,age)

使用列表或者字典comprehension

# badmylist=range(20)odd_list=[]foreinmylist:ife%2==1:odd_list.append(e)# goododd_list=[eforeinmylistife%2==1]# baduser_list=[{'name':'lucy','email':'lucy@g.com'},{'name':'lily','email':'lily@g.com'}]user_email={}foruserinuser_list:if'email'inuser:user_email[user['name']]=user['email']# good{user['name']:user['email']foruserinuser_listif'email'inuser}

条件判断时,避免直接和True, False, None进行比较(==)

# badifl==[]:pass# goodifl:# 实际调用l.__len__() == 0pass# badifsomething==None:# good, None 是单例对象ifsomethingisNone:

使用enumerate代替for循环中的index变量访问

# badmy_container=['lily','lucy','tom']index=0forelementinmy_container:print'{}{}'.format(index,element)index+=1# goodforindex,elementinenumerate(my_container):print'%d%s'%(index,element)

避免使用可变(mutable)变量作为函数参数的默认初始化值

# baddeffunction(l=[]):l.append(1)returnlprintfunction()printfunction()printfunction()# print[1][1,1][1,1,1]# good 使用None作为可变对象占位符deffunction(l=None):iflisNone:l=[]l.append(1)returnl

一切皆对象

# baddefprint_addition_table():forxinrange(1,3):foryinrange(1,3):print(str(x+y)+'\n')defprint_subtraction_table():forxinrange(1,3):foryinrange(1,3):print(str(x-y)+'\n')defprint_multiplication_table():forxinrange(1,3):foryinrange(1,3):print(str(x*y)+'\n')defprint_division_table():forxinrange(1,3):foryinrange(1,3):print(str(x/y)+'\n')print_addition_table()print_subtraction_table()print_multiplication_table()print_division_table()# good, python一切都是对象,可以函数作为参数,类似技巧可以用来简化代码importoperatorasopdefprint_table(operator):forxinrange(1,3):foryinrange(1,3):print(str(operator(x,y))+'\n')foroperatorin(op.add,op.sub,op.mul,op.div):print_table(operator)

防御式编程EAFP vs LBYL

  • EAFP:easier to ask forgiveness than permission

  • LBYL:look before you leap

EAFP可以理解成一切按正常的逻辑编码,不用管可能出现的错误,等出了错误再说;而LBYL就是尽可能每写一行代码,都要提前考虑下当前的前置条件是否成立;

# LBYLdefgetPersonInfo(person):ifperson==None:print'person must be not null!'printperson.info# EAFPdefgetPersonInfo(person):try:printperson.infoexceptNameError:print'person must be not null!'

其实用EAFP风格的代码最大的好处是代码逻辑清晰,而LBYL会导致本来两句话说清楚的事,往往因为穿插了很多条件检查的语句使代码逻辑变得混乱。Python社区更提倡EAFP形式的。另外还有一个原因,在高并发场景下, if条件如果是个表达式,会造成一致性问题,这个时候必须用EAFP形式。这个可以参考Glow团队的技术博客[Glow cache structure](http://tech.glowing.com/cn/glow-cache-structure).

用dict对象完成switch...case...的功能

# baddefapply_operation(left_operand,right_operand,operator):ifoperator=='+':returnleft_operand+right_operandelifoperator=='-':returnleft_operand-right_operandelifoperator=='*':returnleft_operand*right_operandelifoperator=='/':returnleft_operand/right_operand# gooddefapply_operation(left_operand,right_operand,operator):importoperatorasopoperator_mapper={'+':op.add,'-':op.sub,'*':op.mul,'/':op.truediv}returnoperator_mapper[operator](left_operand,right_operand)

访问tuple的数据项时,可以用namedtuple代替index的方式访问

# badrows=[('lily',20,2000),('lucy',19,2500)]forrowinrows:print'{}`age is{}, salary is{} '.format(row[0],row[1],row[2])# goodfromcollectionsimportnamedtupleEmployee=namedtuple('Employee','name, age, salary')forrowinrows:employee=Employee._make(row)print'{}`age is{}, salary is{} '.format(employee.name,employee.age,employee.salary)

用isinstance来判断对象的类型

因为在python中定义变量时,不用像其它静态语言,如java, 要指定其变量数据类型,如int = 4. 但是这并不意味在python中没有数据类型,只是一个变量的数据类型是在运行的时候根据具体的赋值才最终确定。比如下面的代码是计算一个对象的长度值,如果是序列类型(str,list,set,dict)的, 直接调用len方法,如果是True, False, None则返回1,如果是数值的,则返回其int值.

# baddefget_size(some_object):try:returnlen(some_object)exceptTypeError:ifsome_objectin(True,False,None):return1else:returnint(some_object)print(get_size('hello'))print(get_size([1,2,3,4,5]))print(get_size(10.0))# gooddefget_size(some_object):ifisinstance(some_object,(list,dict,str,tuple)):returnlen(some_object)elifisinstance(some_object,(bool,type(None))):return1elifisinstance(some_object,(int,float)):returnint(some_object)

用with管理操作资源的上下文环境

在一个比较典型的场景里,如数据库操作,我们操作connection时一般要正常关闭连接,而不管是正常退出还是异常退出。如下:

# badclassConnection(object):defexecute(self,sql):raiseException('ohoh, exception!')defclose(self):print'closed the Connection'try:conn=Connection()conn.execute('select * from t_users')finally:conn.close()# goodclassConnection(object):defexecute(self,sql):raiseException('ohoh, exception!')defclose(self):print'closed the Connection'def__enter__(self):returnselfdef__exit__(self,errorType,errorValue,error):self.close()withConnection()asconn:conn.execute('select * from t_users')

使用generator返回耗费内存的对象

# baddeff():# ...returnbiglist# gooddeff():# ...foriinbiglist:yieldi

更多资源: