优化 pythonic

使用python已经有很长一段时间了,在比赛中python语言的简洁易懂性给了我很大的帮助。当对一项技能使用的熟练度到达一定程度的时候,就该重新入门了。本文章将长期保持更新,收集记录各种python黑魔法,努力使自己的代码变得更加pythonic!

变量交换

1
a,b = b,a


对可变字符串不建议再使用temp = “(“+str(i)+”,”+str(j)+”)”的写法,给两种替换:

1
2
temp = "({x},{y})".format(x=str(i), y=str(j))
temp = "(%(x),%(y))" % {'x':str(i), 'y':str(j)}


类似于C里面的三元操作符:

1
X if X<Y else Y


直接生成的列表(不是那种定义后一直要修改的)

1
2
fr = open("F://xie.txt")
list = [i for i in fr.readlines()]


python装饰器
作用就是为函数外加一层代码,可以用于日志记录,函数运行时间记录,对于不合适的函数进行代码补充等等场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def runTime(tag = True):
if tag == True:
def _deco(func):
def wrapper(*args, **kwargs):
startTime = time.time()
retu = func(*args, **kwargs)
endTime = time.time()
print ("RunTime is {time}".format(time=endTime-startTime))
return retu
return wrapper
else:
def _deco(func):
return func
return _deco
@runTime(True)
def myFunc(path):
fr = open(path)
list = [i for i in fr.readlines]
myFunc("F://xie.txt")

@runTime(True)相当于:myFunc = runTime(True)(myFunc(path))

调用逻辑为:

  1. runTime(True) 返回_deco 因此等价于 _deco函数
  2. _deco(myFunc(path))返回wrapper 因此等价于 wrapper函数
  3. 所以myFunc 等价于 执行逻辑之后的wrapper(path)函数

装饰器书写需要把握的重点是:

  • 装饰器的本质是函数转换,经过@之后的那个函数其实最后都是变为装饰代码后的wrapper函数
  • 基本的函数转换方式就是在每层函数中定义个子函数,然后逻辑执行后return 子函数

python函数中的可变参数:
其实实现原理很简单,def xie(args, **kwargs)中的args就相当于一个list, **kwargs就相当于一个dict,只是python为方便使用做出了进一步定义

1
2
3
4
5
6
7
8
9
10
11
12
13
def xie(farg, *args)
xie(1, 'two', 3) ==> xie(1, ['two',3])
def xie(farg, **kwargs)
xie(1, url='/xss', method='get') ==> xie(1, {"url":'/xss', 'method':'get'})
def xie(arg1, arg2, arg3)
args = [2, 3]
xie(1, *args) ==> xie(1, 2, 3)
def xie(arg1, arg2, arg3)
kwargs = {'arg1':1, 'arg2':2, 'arg3':3}
xie(**kwargs) ==> xie(1, 2, 3)


迭代器中使用计数模式

1
2
3
fr = open("F://xie.txt", 'r')
for index, i in enumerate(fr.readlines(), 1):
print ("{index}:{i}".format(index=index, i=i))

将迭代列表用enumerate对象封装,每次迭代值返回两个————index, data。
同时enumerate()的第二个参数用于指定index的起始值,默认为0


对于对象的迭代器遍历如果只是为了循环检测是否存在某种情况,可以这样写:

1
[row[1]==0 and row[2]!='Yes' for row in rows]

之后使用any() all() 函数做检测
any([1,0,0])列表中存在1即返回真 all([1,1,1])列表中全为真则返回真
因此具体可以这样写

1
any([row[1]==0 and row[2]!='Yes' for row in rows])


之前对dict的操作认识太浅显,重新整理下dict操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
获取字典中的值,get()函数支持默认参数方法,在没有键值的时候使用默认参数
dict.get('xie', 'fei')
检测键是否存在,存在会返回对应的值,不存在会返回None
dict.get('xie')
另一种方法是在dict.keys()列表中寻找
返回dict中的所有键:
dict.keys()
返回dict中所有值:
dict.values()
更新字典,也就是添加没有的键值对,为键对应的值改变的进行更新。类似于加运算吧
dict.update(dict2)


使用defaultdict类型来进行遍历的结果记录
在对遍历结果统计时经常使用dict类型来记录,但dict在这种情况下有个问题就是,如果是第一次引用一个键,dict[‘xie’] += 1就会出现问题,需要先dict[‘xie’] = 0,再dict[‘xie’] += 1,而defaultdict会在dict[]遇到新的键时为其分配指定的值

1
2
3
4
5
6
from collections import defaultdict
list = [1,2,3,4,5,6,3,4,2,1,8,6,5]
dict = defaultdict(int)
for i in list:
dict[i]+=1


更加健壮的python程序需要进行参数检查:

要检查的数据有:

  1. 用户输出的数据
  2. 从文件中解析出来的数据,如从网页中解析出来的数据,从txt中获取的数据

需要在以下几个地方做参数检查:

  1. 最初遇到这种参数时就做出了检查
  2. 必须保证安全性关键的子函数,如果def download(url)
  3. 检测函数中,经常会做切片分析检测,要防止越界