Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/287.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/8/sorting/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
为什么dict比python中的if-else更快?_Python_Performance_Python 2.7_If Statement_Dictionary - Fatal编程技术网

为什么dict比python中的if-else更快?

为什么dict比python中的if-else更快?,python,performance,python-2.7,if-statement,dictionary,Python,Performance,Python 2.7,If Statement,Dictionary,我试着比较dict和if-else,后者的速度更快,如下所示 d = { str : lambda x: "'%s'" % str(x), int : lambda x: str(x), float: lambda x: str(x), } items = ['a', 'b', 'c', 1, 2, 3, 4, 5, 1.0] def use_dict(): r = [] for i in items: r.append(d[type

我试着比较dict和if-else,后者的速度更快,如下所示

d = {
    str  : lambda x: "'%s'" % str(x),
    int  : lambda x: str(x),
    float: lambda x: str(x),
}
items = ['a', 'b', 'c', 1, 2, 3, 4, 5, 1.0]

def use_dict():
    r = []
    for i in items:
        r.append(d[type(i)](i))
    return r

def use_if():
    r = []
    for i in items:
        if isinstance(i, str):
            r.append("'%s'" % str(i))
        elif isinstance(i, (int, float)):
            r.append(str(i))
    return r

if __name__ == '__main__':

    from timeit import timeit

    print 'use_dict:', timeit(use_dict)
    # -> use_dict: 9.21109666657

    print 'use_if  :', timeit(use_if)
    # -> use_if  : 10.9568739652

我发现迪克特比其他人快。这意味着当我想写一个switch语句时,dict是更好的解决方案。但我有一个疑问,为什么dict更快?任何人都可以解释。谢谢。

我猜这是因为在
项中的元素不是字符串的情况下,
if..elif
解决方案实际上会调用
isinstance()
函数两次,这可能会增加成本。python中的函数调用代价高昂

而您的
dict
解决方案在所有情况下只调用
type()
一次

例如,我将
项的列表
转换为所有字符串,而
if..elif
解决方案的速度更快-

d = {
    str  : lambda x: "'%s'" % str(x),
    int  : lambda x: str(x),
    float: lambda x: str(x),
}
items1 = ['a', 'b', 'c', 1, 2, 3, 4, 5, 1.0]
items = ['a','b','c','d','e','f','g','h','i','j']

def use_dict():
    r = []
    for i in items:
        r.append(d[type(i)](i))
    return r

def use_if():
    r = []
    for i in items:
        if isinstance(i, str):
            r.append("'%s'" % str(i))
        elif isinstance(i, (int, float)):
            r.append(str(i))
    return r

if __name__ == '__main__':

    from timeit import timeit

    print('use_dict:', timeit(use_dict))

    print('use_if  :', timeit(use_if))
在所有字符串上运行它的结果-

C:\Users\anandsk>python a.py
use_dict: 7.891252114975529
use_if  : 6.850442551614534

如果您想了解代码的执行方式,请查看模块

一个简单的例子

import dis

# Here are the things we might want to do
def do_something_a():
    print 'I did a'


def do_something_b():
    print 'I did b'


def do_something_c():
    print 'I did c'


# Case 1
def f1(x):
    if x == 1:
        do_something_a()
    elif x == 2:
        do_something_b()
    elif x == 3:
        do_something_c()


# Case 2
FUNC_MAP = {1: do_something_a, 2: do_something_b, 3: do_something_c}
def f2(x):
    FUNC_MAP[x]()


# Show how the functions execute
print 'Case 1'
dis.dis(f1)
print '\n\nCase 2'
dis.dis(f2)
…输出

Case 1
 18           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (1)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_FALSE       22

 19          12 LOAD_GLOBAL              0 (do_something_a)
             15 CALL_FUNCTION            0
             18 POP_TOP
             19 JUMP_FORWARD            44 (to 66)

 20     >>   22 LOAD_FAST                0 (x)
             25 LOAD_CONST               2 (2)
             28 COMPARE_OP               2 (==)
             31 POP_JUMP_IF_FALSE       44

 21          34 LOAD_GLOBAL              1 (do_something_b)
             37 CALL_FUNCTION            0
             40 POP_TOP
             41 JUMP_FORWARD            22 (to 66)

 22     >>   44 LOAD_FAST                0 (x)
             47 LOAD_CONST               3 (3)
             50 COMPARE_OP               2 (==)
             53 POP_JUMP_IF_FALSE       66

 23          56 LOAD_GLOBAL              2 (do_something_c)
             59 CALL_FUNCTION            0
             62 POP_TOP
             63 JUMP_FORWARD             0 (to 66)
        >>   66 LOAD_CONST               0 (None)
             69 RETURN_VALUE


Case 2
 29           0 LOAD_GLOBAL              0 (FUNC_MAP)
              3 LOAD_FAST                0 (x)
              6 BINARY_SUBSCR
              7 CALL_FUNCTION            0
             10 POP_TOP
             11 LOAD_CONST               0 (None)
             14 RETURN_VALUE
…因此很容易看出哪个函数执行的指令最多

至于哪个速度更快,您必须通过分析代码来检查

if/elif/else结构将提供给它的键逐个与一系列可能的值进行比较,直到在某个if语句的条件中找到匹配项,然后从if块中读取它应该执行的内容。这可能需要很长时间,因为每次查找都必须进行大量检查(
n/2
,对于
n
可能的值)

if语句序列比switch语句更难优化的原因是,条件检查(在C++中的parens中)可能会改变下一次检查中涉及的某个变量的状态,因此必须按顺序进行。switch语句的限制消除了这种可能性,所以顺序并不重要(我认为)

Python字典。这个想法是这样的:如果你可以处理任意大的数字,并且有无限的RAM,你可以创建一个巨大的函数指针数组,只要把你的查找值转换成一个整数并使用它作为索引,它就会被索引。查找几乎是即时的

当然,您不能这样做,但您可以创建一个长度可管理的数组,将查找值传递给(根据查找值生成一些整数),然后将结果与数组的长度成%以获得该数组边界内的索引。这样,查找所需的时间与调用一次哈希函数、取模和跳转到索引所需的时间相同。如果不同的可能查找值的数量足够大,则与那些n/2条件检查相比,哈希函数的开销可以忽略不计


(实际上,由于许多不同的查找值将不可避免地映射到同一个索引,这并不是那么简单。您必须检查并解决可能的冲突,这可以通过多种方式完成。尽管如此,其要点如上所述。)

这不仅仅是对
dict
if
的测试,因为你同时在测试
type(i)=
vs
isinstance
。在得出广泛的结论之前,最好一次测试一件事。此外,看起来您可能正在尝试编写
repr()
已经可以为您做的东西。不知道“dis”,但它看起来非常有用。谢谢你提出来![复制警报]