为什么这些算法在执行时间上如此不同?在Python中,walrus运算符是否耗时更少?

e0bqpujr  于 2023-05-08  发布在  Python
关注(0)|答案(1)|浏览(95)

我在输入模块中创建操作TypeVar的函数时,遇到了一个问题。我的函数确实可以工作,但我想让它更快,所以我使用了timeit模块来测试一些不同的版本。
然而结果并不是我所期望的。

清除一些潜在的询问:

check_type(object , type)是一个用来测试一个对象是否对应于一个类型的函数(目前非常耗时)。
isTypeVar(type)测试类型是否为TypeVar。
NullType是一个不能描述对象的类型,所以当用check_type测试它时,它总是返回False。
restrict_TypeVar_for_object(typeVar , object)是一个函数,我创建它是为了删除typeVar中所有不对应于object的约束。
如何计算函数的时间:

from timeit import timeit

func_version = """..."""
task="""..."""
timeit(task , setups=func_version , number=10_000_000)

下面是我计时的任务(正如你在上面看到的我已经重复了10 000 000次):

Number = int | float
T = TypeVar("T" , int , str , Number)

restrict_TypeVar_for_object(T , 5)
#   --> TypeVar("T" , int , Number)

我的测试:

  • 第1版:
def restrict_TypeVar_for_object(ty , obj):
    if not isTypeVar(ty) : #Just to be sure that ty is a TypeVar
        raise ValueError ('Expected a TypeVar as an argument')

    if not ty.__constraints__ :
        return type(obj)

    lCons=[cons for cons in ty.__constraints__ if check_type(obj , cons)]
    return (TypeVar(ty.__name__ , *lCons)
            if len(lCons)>1 else
            lCons[0]
            if lCons else
            NullType)

需要:378.5483768 s

  • 第二版:
def restrict_TypeVar_for_object(ty , obj):
    if not isTypeVar(ty) : #Just to be sure that ty is a TypeVar
        raise ValueError ('Expected a TypeVar as an argument')

    if not ty.__constraints__ :
        return type(obj)

    return (TypeVar(ty.__name__ , *lCons)
            if len(lCons:=[cons for cons in ty.__constraints__ if check_type(obj , cons)])>1 else
            lCons[0]
            if lCons else
            NullType)

需要:376.9706139秒

  • 第三版:
def restrict_TypeVar_for_object(ty , obj):
    if not isTypeVar(ty) : #Just to be sure that ty is a TypeVar
        raise ValueError ('Expected a TypeVar as an argument')

    if not ty.__constraints__ :
        return type(obj)

    return (TypeVar(ty.__name__ , *lCons[:-1])
            if len(lCons:=[c for c in ty.__constraints__ if check_type(obj,c)]+[NullType]) > 2
            else
            lCons[0])

需要:391.5145658000001 s
如你所见第二个是最快的。但是我没想到第三个会比另一个慢。坦率地说,我甚至期待它是最快的一个,因为我在这一个做了更少的if语句。
我有两个假设来解释为什么会这样:

  • 首先,海象运算符但如果是,为什么第2版是最快的。
    第二,我在lCons的末尾添加了[NullType],但我不知道为什么会这么耗时。
pprl5pva

pprl5pva1#

首先,正如tdelaney指出的,它们执行时间的差异来自于第三版中创建了许多列表

  • [c for c in ty.__constraints__ if check_type(obj,c)]是所有版本通用的。
  • [NullType],由lCons + [NullType]lCons[:-1]的级联产生的列表,其专用于第三版本。

现在是我问题的第二部分,关于海象运算符的时间消耗
walrus操作符比简单的分配花费更多的时间,如下面的测试所示:

from timeit import timeit

#Assignement statement :
tsk1="""
a = 5
"""

#Assignement expression :
tsk2="""
(a := 5)
"""

print(timeit(tsk1 , number=10_000_000))
print(timeit(tsk2 , number=10_000_000))

tsk1重复10 000 000次拍摄:0.7440573999992921秒
tsk2重复10 000 000次拍摄:1.0597749000007752秒

  • 我做了很多次测试,结果总是大致相同。

最后,下面是我应该如何在Python中实现我的restrict_TypeVar_for_object(typeVar , object)函数:

def restrict_TypeVar_for_object(ty , obj):
    if not isTypeVar(ty) : #Just to be sure that ty is a TypeVar
        raise ValueError ('Expected a TypeVar as an argument')

    if not ty.__constraints__ :
        return type(obj)
    
    lCons = [cons for cons in ty.__constraints__ if check_type(obj , cons)]
    return (TypeVar(ty.__name__ , *lCons)
            if len(lCons)>1 else
            [*lCons , NullType][0])

重复10 000 000次需要:**383.57044309999765
然而,正如你所看到的,它仍然需要太多的时间,所以我尝试了海象运算符:

def restrict_by_object(ty , obj):
    if not isTypeVar(ty) : #Just to be sure that ty is a TypeVar
        raise ValueError ('Expected a TypeVar as an argument')

    if not ty.__constraints__ :
        return type(obj)

    return (TypeVar(ty.__name__ , *lCons)
            if len(lCons:=[cons for cons in ty.__constraints__ if check_type(obj , cons)])>1 else
            [*lCons , NullType][0])

这需要:373.867099199997 s

  • 我仍然不知道为什么海象运算符在这种情况下更好,但一旦我明白了,我会更新这个答案。

相关问题