别笑!Python 新手这五大坑你躲不过

发表于:2022-1-25 09:31

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:软件测试狂阿沐    来源:CSDN

  对于Python新手来说,写代码很少考虑代码的效率和简洁性,因此容易造成代码冗长、执行慢,这些都是需要改进的地方。本文是想通过几个案列给新手一点启发,怎样写python代码更优雅。
  01. 不喜欢使用高级数据结构
  sets(集合)
  很多新手忽视sets(集合)和tuple(元组)的强大之处.
  例如,取两个列表交集:
  def common_elements(list1, list2):    
      common = []        
      for item1 in list1:                
          if item1 in list2:                        
              common.append( item1 )        、
      return common

  这样写会更好:
  def common_elements(list1, list2):
      common = set(list1).intersection(set(list2))
      return list(common)

  dic(字典)
  新手枚举(访问和取出)字典的键和对应值,认为对应值必须通过键来访问,往往会这样做:
  my_dict = {'a':1,'b':2}
  for key in my_dict:        
      print(key, my_dict[key])

  有一个更优雅的方法可以实现:
  my_dict = {'a':1,'b':2}
      for key, value in my_dict.items():    
      print(key, value)

  对大部分项目来说,这样写会更加有效率。

  tuple(元组)
  元组一旦创建就无法更改元素,看似没有什么用处,其实元组的作用大着呢!很多函数方法都会返回元组,比如enumerate()和dict.items(),并且可以在函数中使用元组,返回多个值。还能够很方便地从元组中提取信息:
  a,b = ('cat','dog')

  上面元组中有两个元素,分别被赋给a,b。如果有多个值,同样可以提取:
  a,b,c = ('cat','dog','tiger')
  print(a,b,c)

  提取首、尾两个元素:
  first,*_,end = (1,2,3,4,5,6)
  print(first,end)
  # 输出:1、6

  提取首、中、尾三部分:
  first,*middle,end = (1,2,3,4,5,6)
  print(first,middle,end)
  # 输出:1、[2, 3, 4, 5]、6

  元组还可以用来交换变量:
  (a,b,c) = (c,a,b)
  
  上面a变成之前的c,b变成之前的a,c变成之前的b。元组也能作为字典的键,所以如果你需要存储数据,可以使用带有元组键的字典,比如说经纬度数据。

  02. 不喜欢使用上下文管理器
  新手可能会习惯这样进行读取文件操作:
  if os.path.exists(data_file_path):    
      data_file = open(data_file_path,'r')
  else:    
      raise OSERROR
  print( data_file.read())
  data.close()

  这样写会有几个明显的问题:
  ·可能出现文件存在,但文件被占用,无法读取的情况
  · 可能出现文件可以被读取,但操作文件对象出现报错的情况
  · 可能出现忘记关闭文件的情况

  如果使用with…语句,问题就迎刃而解了:
  with open(data_file_path,'r') as data_file:
      print(data_file.read)

  这样可以捕获任何打开文件或处理数据时的异常情况,并且在任务处理完后自动关闭文件。
  python初学者可能不太了解上下文管理器的神奇之处,它真的能带来巨大的便利。

  03. 不喜欢使用标准库
  标准库itertools和collections仍然很少被初学者使用
  itertools
  如果你看到下面的任务:
  list1 = range(1,10)
  list2 = range(10,20)
  for item1 in list1:
      for item2 in list1:
          print(item1*item2)

  这是一个嵌套循环操作,为提高代码效率,完全可以用product()函数替代嵌套循环:
  from itertools import product
  list1 = range(1,10)
  list2 = range(10,20)
  for item1,item2 in product(list1, list2):
      print(item1*item2)

  这两段代码的结果完全一样,但使用标准库函数明显更加简洁高效。itertools还有很多方便操作迭代对象的函数,比如:
  ·count()函数会创建一个无限迭代器
  · cycle()函数会把传入的序列无限重复下去
  · chain()可以把多个迭代对象串联起来
  · group()函数可以把迭代其中相邻的重复元素挑出来,放在一起
  有兴趣可以详细看看itertools库的各种神奇函数。

  collections
  新手对python集合模块了解的可能并不多,你可能会遇到这样的情形:
  consolidated_list = [('a',1),('b',2),('c',3),('b',4)]
  items_by_id = {}
  for id_, item in consolidated_list:
      if id_ not in items_by_id: 
          items_by_id[id_] = []
      if id_ in items_by_id:
          items_by_id[id_].append(item)

  上面代码构建了一个字典,依次向字典中添加信息,如果某个键已经存在,则以某种方式修改该键的值;如果某个键不存在,则添加对应键值对。
  这种算法非常常见,你可以用collects模块的defaultdict()函数来实现同样效果:
  from collections import defaultdict
  items_by_id = defaultdict(list)
  consolidated_list = [('a',1),('b',2),('c',3),('b',4)]
  for id_, item in consolidated_list:
      items_by_id[id_].append(item)

  在此列中,defaultdict()接受一个list作为参数,当键不存在时,则返回一个空列表作为对应值。
  有时候我们会遇到统计词频的案例,比如:
  # 统计词频
  colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
  result = {}
  for color in colors:
      if result.get(color)==None:
          result[color]=1
      else:
          result[color]+=1
  print (result)
  # 输出 {'red': 2, 'blue': 3, 'green': 1}
 
  完全可以用defaultdict()函数实现上面的计数功能:
  colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
  d = defaultdict(int)
  for color in colors:
      d[color] += 1
  print(d)

  更简单的方法用collections模块的Counter()函数:
  from collections import Counter
  colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
  c = Counter(colors)
  print (dict(c))

  对于备份文件,新人往往会用system模块:
  from  os import system
  system("xcopy e:\\sample.csv  e:\\newfile\\")

  其实shutil模块更好用:
  import shutil
  shutil.copyfile('E:\\q.csv', 'e:\\movie\\q.csv')

  因为shutil会很详细地报告错误和异常。

  04. 不喜欢使用异常处理
  无论老手新手都应该在写代码的时候进行异常处理操作,这样可以使代码更加健壮。异常处理一般会用try…except语句。

  05. :不喜欢使用生成器
  除非你的list十分复杂,并且频繁调用,否则都建议使用生成器,因为它非常节省内存,举个例子:
  def powers_of_two(max=20000):
      i = 0
      powers = []
      while 2**i < max:
          powers.append[2**i]
          i += 1
      return powers

  对于使用次数少、占据大量内存、且容易生成的数据,可以用生成器替代列表存储:
  from itertools import count, takewhile
  def powers_of_two(max=20000):
      for index in takewhile(lambda i: 2**i < max, count(start=0)):
          yield 2**index

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号