Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么`试试。。。除了`比`如果`快之外?_Python_Performance_Try Catch_Python 3.4 - Fatal编程技术网

Python 为什么`试试。。。除了`比`如果`快之外?

Python 为什么`试试。。。除了`比`如果`快之外?,python,performance,try-catch,python-3.4,Python,Performance,Try Catch,Python 3.4,在我的代码中,我有一个列表l,我正在从中创建一个列表字典。(我正在对具有相同键的对象进行分组。通过一个try语句和一个if条件来实现它,我在line_profiler中注意到前者似乎效率更高: Line # Hits Time Per Hit % Time Line Contents ============================================================== 293 44378450 59805

在我的代码中,我有一个列表
l
,我正在从中创建一个列表字典。(我正在对具有相同
键的对象进行分组。通过一个
try
语句和一个
if
条件来实现它,我在line_profiler中注意到前者似乎效率更高:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================

   293  44378450     59805020      1.3     16.9       for element in l:

                                                        # stuff that compute 'key' from 'element'

   302   2234869      2235518      1.0      0.6              try:                                                         
   303   2234869     82486133     36.9     23.3                  d[key].append(element)                              
   304     57358        72499      1.3      0.0              except KeyError:                                             
   305     57358      1758248     30.7      0.5                  d[key] = [element]  
vs:


我知道,使用
try
,只有在引发异常时才会进入
(因此,在很少的异常情况下,它的总体成本低于每次测试条件),但在这里,即使是每次命中的
时间,异常(1.3+30.7µs)也比测试条件(36.5µs)慢。我认为引发异常比检查一个键是否在字典中花费更多(
中的
只测试散列键,不?这不是行搜索)。那么这是为什么呢?

额外的运行时来自
.keys()
调用。如果您想阻止该额外呼叫,并且仍然使用
If
else
,请尝试以下操作:

obj = d.get(key)
if obj:
      obj.append(element)
else:
      d[key] = [element]
或者,您可以使用
defaultdict
在后台执行此操作。例如:

from collections import defaultdict
d = defaultdict(list)
d['123'].append('abc')

您应该认为,在每一次迭代中,如果条件检查,您就会失去一些测试时间。如果您不引发异常,那么使用try-except,您的代码会更快,否则处理异常会花费更多的时间

换句话说,如果您确信您的异常是异常的(它只发生在异常情况下),那么使用try-except会更便宜。否则,如果您在大约50%的情况下排除了异常,那么最好使用if


(“请求原谅比请求允许更容易”)

尝试……除非实际引发的异常数量与执行循环的次数相当,否则
的速度较慢。在您的情况下,异常只会在循环迭代中引发2.5%

让我们分析以下四种情况-

def func1():
    l = [1,2,3,4]
    d = {}
    for e in l:
        k = e - 1
        try:
            d[k].append(e)
        except KeyError:
            d[k] = [e]
    return d


def func2():
    l = [1,2,3,4]
    d = {}
    for e in l:
        k = e - 1
        if k in d.keys():
            d.get(k).append(e)
        else:
            d[k] = [e]
    return d

def func3():
    l = [1,2,3,4]
    d = {}
    for e in l:
        k = 1
        try:
            d[k].append(e)
        except KeyError:
            d[k] = [e]
    return d


def func4():
    l = [1,2,3,4]
    d = {}
    for e in l:
        k = 1
        if k in d.keys():
            d.get(k).append(e)
        else:
            d[k] = [e]
    return d
此操作的计时结果-

In [7]: %timeit func1()
The slowest run took 4.17 times longer than the fastest. This could mean that an intermediate result is being cached
100000 loops, best of 3: 2.55 µs per loop

In [8]: %timeit func2()
1000000 loops, best of 3: 1.77 µs per loop

In [10]: %timeit func3()
The slowest run took 4.34 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 2.01 µs per loop

In [11]: %timeit func4()
The slowest run took 6.83 times longer than the fastest. This could mean that an intermediate result is being cached
100000 loops, best of 3: 2.4 µs per loop
  • 对于
    func1()
    func2()
    ,每个元素都会进入一个单独的列表,因此对于每个键,
    try..except
    块会引发并捕获异常。在这种情况下,
    func2()
    更快

  • func3()
    func4()
    的情况下,异常只引发一次,因此异常的开销只发生一次,而每个键(即使存在)的条件仍会被检查,这就是为什么在这种情况下,
    try..except
    更快


  • 我猜在您的情况下可能会发生类似的情况,同一个键被计算多次,因此使用
    try。您可以查看列表中有多少实际元素,以及字典中有多少键,以确定这是否是原因

    假设
    hits
    列是特定行的执行次数,您可以看到,该行-

    d[key].append(element)
    

    执行了2234869次,而异常只引发了-57358次,仅占元素总数的2.56%。

    这是Python 2.x吗?它是Python 3.4。顺便问一下,为什么要投否决票?
    if
    版本必须查找
    键两次,一次在
    if
    测试中,一次在
    get
    中。如果这是Python 2,它会更慢,因为
    d.keys()
    是一个列表,而不是一个视图,所以查找涉及一个线性搜索,而不是一个基于散列的测试集。Pythonic的方法是使用
    d=defaultdict(list)
    。然后
    d[key].append(element)
    将始终有效。好的,但是如果
    版本(如果该键存在),您仍要在
    中进行两次查找。FWIW,关于
    if
    vs
    的相对速度有一些很好的信息,除了
    
    d[key].append(element)