接上一篇RPA优雅写Python代码(一)。6.列表索引的各种风骚操作Python引入负整数作为数组索引,绝对是个大动作。想一想,在C/C++中,如果要数组的最后一个元素,必须先获取数组的长度,减一再做索引,严重影响思维的连贯性。Python语言之所以成功,我个人认为,在众多因素中,列表操作的便利性是不容忽视的。参见:>>>a=[0,1,2,3,4,5]>>>a[2:4][2,3]>>>a[3:][3,4,5]>>>a[1:][1,2,3,4,5]>>>a[:][0,1,2,3,4,5]>>>a[::2][0,2,4]>>>a[1::2][1,3,5]>>>a[-1]5>>>a[-2]4>>>a[1:-1][1,2,3,4]>>>a[::-1][5,4,3,2,1,0]如果你熟悉这些并且经常使用它们,那么下面的用法,你一定会感觉很神奇:>>>a=[0,1,2,3,4,5]>>>b=['a','b']>>>a[2:2]=b>>>a[0,1,'a','b',2,3,4,5]>>>a[3:6]=b>>>a[0,1,'a','a','b',4,5]7。lambda函数lambda是一个匿名函数,这个函数在定义匿名函数的地方使用,而不是在其他地方使用,所以不需要给它起函数名。下面是一个用于求和的匿名函数。有两个输入参数,x和y。函数体为x+y,省略return关键字。>>>lambdax,y:x+yat0x000001B2DE5BD598>>>>(lambdax,y:x+y)(3,4)#因为匿名函数没有名字,所以使用时要加括号把它包起来。匿名函数一般不会单独使用,而是与其他方法结合使用,为其他方法提供内置算法或判断条件。例如,在使用排序函数sorted对多维数组或字典进行排序时,可以指定排序规则。>>>a=[{'name':'B','age':50},{'name':'A','age':30},{'name':'C','age':40}]>>>sorted(a,key=lambdax:x['name'])#按名字排序[{'name':'A','age':30},{'name':'B','age':50},{'name':'C','age':40}]>>>sorted(a,key=lambdax:x['age'])#按年龄排序[{'name':'A','age':30},{'name':'C','age':40},{'name':'B','age':50}]再一次对数组元素求平方的示例,这次使用map函数:>>>a=[1,2,3]>>>foriteminmap(lambdax:x*x,a):print(item,end=',')1,4,9,8.yield与生成器和迭代器要理解yield,首先要理解生成器。要了解生成器,首先要了解迭代器(iterator)。说到py2时代,range()返回的是一个列表,但是如果使用range(10000000)会消耗大量内存资源,所以py2又多了一个xrange()来解决这个问题。py3只保留了xrange(),却写了range()。xrange()返回的是一个迭代器,可以像列表一样遍历,但不会占用太多内存。生成器(generator)是一种特殊的迭代器,只能遍历一次,遍历结束后自动消失。总之,无论是迭代器还是生成器,都是为了避免使用列表,从而节省内存。那么,如何获得迭代器和生成器呢?Python有一个内置的迭代函数iter,用来生成一个迭代器。用法如下:>>>a=[1,2,3]>>>a_iter=iter(a)>>>a_iter>>>foriina_iter:print(i,end=',')1,2,3,yield用于构造生成器。比如我们要写一个函数,返回从0到某个正整数的所有整数的平方。传统的代码是这样写的:>>>defget_square(n):result=list()foriinrange(n):result.append(pow(i,2))returnresult>>>print(get_square(5))[0,1,4,9,16]但是如果计算1亿以内所有整数的平方,函数内存开销会非常大,这就是yield大显身手的地方:defget_square(n):foriinrange(n):yield(pow(i,2))>>>a=get_square(5)>>>a>>>foriina:print(i,end=',')0,1,4,9,16,如果再遍历,就没有输出了。9、装饰器Python为我们提供了很多武器,而装饰器是最强大的武器之一。装饰器非常强大。这里我尝试用一??个简单的例子,从需求的角度来说明装饰器的使用和制作过程。如果我们需要定义很多函数,并在运行时显示每个函数的运行时间,解决方案有很多种。例如,可以在调用每个函数之前读取时间戳,然后在每个函数运行完毕后读取时间戳,计算差值;也可以读取每个函数体开始和结束位置的时间戳,最后计算Difference。但是,这两种方法都没有使用装饰器那么简单和优雅。下面的例子很好地证明了这一点。>>>导入时间>>>deftimer(func):defwrapper(*args,**kwds):t0=time.time()func(*args,**kwds)t1=time.time()print('耗时%0.3f'%(t1-t0,))returnwrapper>>>@timerdefdo_something(delay):print('functiondo_somethingstarts')time.sleep(delay)print('functiondo_somethingends')>>>do_something(3)functiondo_somethingstartfunctiondo_somethingend耗时3.077timer()是我们定义的装饰函数,在任何函数(如do_something)定义前使用@附加,等于新定义的函数,作为装饰器函数的输入参数。运行do_something()函数可以理解为执行timer(do_something)。虽然细节复杂,但这样理解不会出太大偏差,更容易掌握装饰器的制作和使用。10.巧妙地使用断言。assert所谓断言就是声明表达式的布尔值必须为真,否则会触发AssertionError异常。严格来说,assert是一种调试手段,不应该在生产环境中使用,但这并不影响我们使用断言来实现一些特定的功能,比如输入参数的格式、类型验证等。>>>defi_want_to_sleep(delay):assert(isinstance(delay,(int,float))),'函数参数必须是整数或浮点数'print('开始休眠')time.sleep(delay)print('sleepWokeup')>>>i_want_to_sleep(1.1)开始睡眠并醒来>>>i_want_to_sleep(2)开始睡眠并醒来>>>i_want_to_sleep('2')Traceback(最近调用最后):文件“”,第1行,在i_want_to_sleep('2')文件“”,第2行,在i_want_to_sleepassert(isinstance(delay,(int,float))),'ThefunctionparametermustbeIntegerorfloatingpointnumber'AssertionError:Thefunctionparametermustbeanintegerorfloatingpointnumber免费下载试用:https://support.i-search.com.cn/