本文将为大家介绍Python中常见的反模式,给大家一个更好的编译方式。1、对Iterable对象使用map()和filter()内置的map和filter可以通过函数式编程的原理帮助我们转换Python中的可迭代对象。这两种方法都接受一个函数和一个可迭代对象作为参数并返回相应的对象。通过将对象作为参数传递给Python中的内置列表构造函数,可以将对象转换为列表。我们经常使用lambda函数作为map和filter函数的参数:my_list=[1,2,3,4,5,6,7,8,9,10]#将每个元素乘以2print(list(map(lambdax:x*2,my_list)))#[2,4,6,8,10,12,14,16,18,20]#过滤偶数print(list(filter(lambdax:x%2==0,my_list)))#[2,4,6,8,10]上面的代码看起来比较繁琐,不清楚。使用列表理解可以实现相同的结果:my_list=[1,2,3,4,5,6,7,8,9,10]#Sameasmapprint([x*2forxinmy_list])#[2,4,6,8,10,12,14,16,18,20]#同filterprint([xforxinmy_listifx%2==0])#[2,4,6,8,10]不使用lambda函数后,列表理解变得更具可读性和简洁性。2.当输入量很大时使用列表推导列表推导帮助我们写出清晰简洁的代码。但是,列表理解总是为可迭代对象中的每个值创建一个列表。当输入量很大时,会导致内存消耗过大的问题:我们的机器可能会死机。生成器表达式结合了列表理解和生成器这两个世界的优点,提供了一种更有效的处理大型输入序列的方法。要创建生成器表达式,只需将列表中的[]括号替换为()括号即可。生成器表达式不是创建一个全新的列表,而是创建一个迭代器。这会减慢创建速度并优化内存分配。我们可以使用next函数或遍历生成器表达式的每个后续元素。my_list=[1,2,3,4,5,6,7,8,9,10]my_gen_expr=(x*2forxinmy_list)print(next(my_gen_expr))print(next(my_gen_expr))#>>#2#4forxinmy_gen_expr:print(x)#>>#6#8#10#12#14#16#18#20注意:生成器表达式是有状态的,复用时要小心。如果要多次使用它,您可能需要重新创建迭代器。3.当不使用range()时,range函数对于迭代整数很有用。foriinrange(10):print(i)在遍历类似列表的数据结构时,我们可以完全依赖for循环语法来访问每个项目。代码如下:my_list=[2,4,6,8,10]foriteminmy_list:print(item)#Output:#2#4#6#8#10但是当想访问索引和元素时我们可以使用listlength下的range方法如下:my_list=[2,4,6,8,10]foriinrange(len(my_list)):print("index:",i,"value:",my_list[i])#Output:#index:0value:2#index:1value:4#index:2value:6#index:3value:8#index:4value:10代码看起来不可读,因为我们必须在列表上调用len然后使用Therange方法包装输出。为了让代码更pythonic,我们不得不提高代码的可读性。更好的方法是在列表对象上调用枚举函数。这将创建一个生成器,生成列表项的索引和值。my_list=[2,4,6,8,10]fori,vinenumerate(my_list):print("index:",i,"value:",v)#Output:#index:0value:2#index:1value:4#index:2value:6#index:3value:8#index:4value:10代码看起来更干净吗?4.字典缺键问题字典具有快速访问、分配、插入和删除的能力,是一种非常流行的数据结构。但是新手开发人员在访问字典中不存在的键时经常会遇到问题。crypto_price={"Bitcoin":64000,"Ethereum":2300,"Dogecoin":0.12}crypto_price["XRP"]处理此类问题的方法之一是检查字典中是否存在密钥,代码如下:key="XRP"ifkeynotincrypto_price:crypto_price[key]=1.2print(crypto_price[key])另一种方法是使用这样的try/except块:key="XRP"try:xrp=crypto_price[key]exceptraiseKeyError:xrp=1.2crypto_price[key]=xrp上面的代码确实达到了我们的目的,但是我们可以通过使用字典方法get来进一步改进。不使用方括号[]访问字典的键,而是使用get方法获取相应键的值。此外,如果密钥不存在,get方法将返回None而不是抛出KeyError。如果缺少键而不是没有键,也可以将参数传递给get方法以获取默认值。key="XRP"ifcrypto_price.get("XRP")isNone:crypto_price["XRP"]=1.2ada=crypto_price.get("ADA",0)#Prints0print(ada)5.惰性关键字和位置参数设计Python函数可以接受位置参数和关键字参数。位置参数是不带等号(=)的名称,后跟默认值。关键字参数后跟一个等号和一个给出其默认值的表达式。由于这种设计,python函数的创建和重用非常灵活。但是,定义函数时错误的设计选择可能会导致代码中出现难以修复的错误。我们以计算复利的函数为例:#Compoundinterestcalculatoryear/monthcompoundinterestdefcalculate_compound_interest(principal,rate,time_in_years,compounded_monthly,to_string):t=1ifcompounded_monthly:t=12amt=principal*(1+rate/(t*100))**(time_in_years*t)ifto_string:returnf"${amt-principal:.2f}"returnamt-principalcalculate_compound_interest(100,5,2,False,False)#10.25调用函数时的一个问题是两个Boolean参数(最后是compounded_monthly和to_string)很容易混淆。这会产生难以追踪的问题。我们可以通过如下更改函数定义来提高可读性:#compoundinterestcalculatoryear/monthcompoundinterestdefcalculate_compound_interest(principal,rate,time_in_years,compounded_monthly=False,to_string=False):通过将两个布尔参数指定为关键字参数,函数调用者可以显式指定布尔值来设置覆盖默认值。calculate_compound_interest(100,5,2,compounded_monthly=True)#10.49413355583269calculate_compound_interest(100,5,2,to_string=True)#'$10.25'但是,这仍然存在一个问题,主要是因为关键字参数是可选的,因为没有什么强制调用者将它们用作关键字参数。所以我们还是可以按照老方法调用函数:calculate_compound_interest(100,5,2,False,False)这个问题的解决方法是在定义函数的时候强制boolean参数只能是关键字:#compoundinterestcalculatoryear/月复利defcalculate_compound_interest(principal,rate,time_in_years,*,#Changedcompounded_monthly=False,to_string=False):我们看到*符号表示位置参数的结束和仅关键字参数的开始。如果这样调用:calculate_compound_interest(100,5,2,False,False)会出现以下错误:---------------------------------------------------------------------TypeErrorTraceback(mostrecentcallast)
