当前位置: 首页 > 面试题库 >

Python性能:是否尝试-否?

郁明诚
2023-03-14
问题内容

在我的一个类中,我有许多方法都从相同的字典中提取值。但是,如果其中一个方法尝试访问不存在的值,则它必须调用另一个方法以使该值与该键关联。

我目前已按以下方式实现此功能,其中findCrackDepth(tonnage)为self.lowCrackDepth [tonnage]分配一个值。

if tonnage not in self.lowCrackDepth:
    self.findCrackDepth(tonnage)
lcrack = self.lowCrackDepth[tonnage]

但是,我也有可能这样做

try:
    lcrack = self.lowCrackDepth[tonnage]
except KeyError:
    self.findCrackDepth(tonnage)
    lcrack = self.lowCrackDepth[tonnage]

我假设两者之间存在性能差异,这与值在字典中的频率有关。这个差异有多大?我正在生成数百万个这样的值(分布在该类的许多实例中的许多词典中),并且每次不存在该值时,它的值可能都会出现两次。


问题答案:

这是一个微妙的问题,因为您需要注意避免“持久的副作用”,并且性能折衷取决于丢失键的百分比。因此,请考虑以下dil.py文件:

def make(percentmissing):
  global d
  d = dict.fromkeys(range(100-percentmissing), 1)

def addit(d, k):
  d[k] = k

def with_in():
  dc = d.copy()
  for k in range(100):
    if k not in dc:
      addit(dc, k)
    lc = dc[k]

def with_ex():
  dc = d.copy()
  for k in range(100):
    try: lc = dc[k]
    except KeyError:
      addit(dc, k)
      lc = dc[k]

def with_ge():
  dc = d.copy()
  for k in range(100):
    lc = dc.get(k)
    if lc is None:
      addit(dc, k)
      lc = dc[k]

以及一系列timeit呼叫,例如:

$ python -mtimeit -s'import dil; dil.make(10)' 'dil.with_in()'
10000 loops, best of 3: 28 usec per loop
$ python -mtimeit -s'import dil; dil.make(10)' 'dil.with_ex()'
10000 loops, best of 3: 41.7 usec per loop
$ python -mtimeit -s'import dil; dil.make(10)' 'dil.with_ge()'
10000 loops, best of 3: 46.6 usec per loop

这表明,缺少10%的密钥,in检查实际上是最快的方法。

$ python -mtimeit -s'import dil; dil.make(1)' 'dil.with_in()'
10000 loops, best of 3: 24.6 usec per loop
$ python -mtimeit -s'import dil; dil.make(1)' 'dil.with_ex()'
10000 loops, best of 3: 23.4 usec per loop
$ python -mtimeit -s'import dil; dil.make(1)' 'dil.with_ge()'
10000 loops, best of 3: 42.7 usec per loop

仅丢失1%的密钥,该exception方法 快(get无论哪种情况,该方法仍然是最慢的一种)。

因此,为了获得最佳性能,除非 绝大多数 (99%以上)的查找成功,否则该in方法是可取的。

当然,还有另一种优雅的可能性:添加像…这样的dict子类:

class dd(dict):
   def __init__(self, *a, **k):
     dict.__init__(self, *a, **k)
   def __missing__(self, k):
     addit(self, k)
     return self[k]

def with_dd():
  dc = dd(d)
  for k in range(100):
    lc = dc[k]

然而…:

$ python -mtimeit -s'import dil; dil.make(1)' 'dil.with_dd()'
10000 loops, best of 3: 46.1 usec per loop
$ python -mtimeit -s'import dil; dil.make(10)' 'dil.with_dd()'
10000 loops, best of 3: 55 usec per loop

…虽然确实很漂亮,但这并不是性能上的赢家-
即便采用这种get方法,或更慢的速度,也要使用外观漂亮的代码来实现。(在defaultdict语义上类似于此类dd,如果适用的话,将是性能上的胜利,但这是因为__missing__在这种情况下,特殊方法是在经过优化的C代码中实现的)。



 类似资料:
  • 问题内容: 我注意到使用pandas的迭代器时性能非常差。 这是别人所经历的吗?它特定于迭代吗?对于一定大小的数据(我正在处理2-3百万行),应该避免使用此功能吗? 在GitHub上进行的讨论使我相信,这是在数据帧中混合时引起的,但是下面的简单示例显示,即使使用一个也存在该问题。这在我的机器上需要36秒: 为什么矢量化运算之类的应用这么快?我想象那里也必须进行逐行迭代。 我无法弄清楚在我的情况下如

  • 我的两个列表中有以下元素,清单1[A F K]和清单2[B A C F K]。清单1的所有元素都在清单2中,因此它应该返回true 我尝试使用list1.containsAll(list2),但它并不支持我。 我尝试在这两个列表中循环,如果找到匹配,我就清空第一个列表中的那个位置,但这不起作用,因为我认为它会受到并发修改的影响。这是我的代码 在这里,subTreeList最终输出[A]。我知道它会

  • 根据Oracle文档 try with resources语句是声明一个或多个资源的try语句。资源是一个对象,在程序完成后必须关闭它。try with resources语句确保在语句末尾关闭每个资源。任何实现java的对象。AutoCloseable,其中包括实现java的所有对象。伊奥。可关闭,可用作资源 如果资源未实现AutoCloseable,则无法在try块中声明,必须在主体部分中声明

  • 问题内容: Kotlin是否可以提高性能?有基准测试吗?Kotlin比Java快吗?我在Kotlin网站上找到了这个。https://kotlinlang.org/docs/reference/comparison- to-java.html 谈论语言功能而不是性能。 问题答案: Kotlin生成的字节码与Java非常相似,因此Kotlin代码的性能在大多数情况下与等效Java代码的性能相同。 内

  • 问题内容: 我目前认为: 当您需要一种可以从中随机检索项目的结构时,请使用 当您要按顺序检索项目时(例如,使用for循环)-请使用 我通常是正确的吗?是否存在不正确的情况? 问题答案: 通常,是的,您是正确的。还有一个组合的数据结构LinkedHashMap,它提供对任意元素的快速访问以及可预测的顺序。 但是,值得注意的是,ArrayList和HashMap分别只是List和Map接口的两个实现。

  • 不管错误情况如何,使用资源尝试是否总是关闭资源?我的意思是考虑以下代码: 会一直关闭吗?我读过Oracle文档,其中说: 无论try语句是正常完成还是突然完成,它都将关闭 因此无论程序正常运行还是抛出异常,它都将起作用。但是,类似或崩溃的情况怎么办?我知道这些条件对块不起作用。那么,使用资源尝试失败的条件是否存在? 这只是我请求的好奇心,谁能说明这一点吗?