【问题标题】:Python decorator to time recursive functions properlyPython 装饰器正确计时递归函数
【发布时间】:2019-10-14 19:07:57
【问题描述】:

我正在编写一段代码用于学习目的,我想比较使用不同算法对列表进行排序所需的时间。我尝试使用装饰器,但由于 mergeSort 函数是递归的,它给了我每次递归的结果。如果可能的话,我想找到一种方法来总结结果。由于我对装饰师很陌生,我不确定在这种情况下可以做什么。有没有办法使用装饰器来实现这个目标?

import random
import functools
import time


def timeIt(func):
    @functools.wraps(func)
    def newfunc(*args, **kwargs):
        startTime = time.time()
        func(*args, **kwargs)
        elapsedTime = time.time() - startTime
        print('function [{}] finished in {} ms'.format(
            func.__name__, int(elapsedTime * 1000)))
    return newfunc


@timeIt
def mergeSort(L):
    if len(L) > 1:
        mid = len(L) // 2
        left = L[:mid] 
        right = L[mid:]
        mergeSort(left)
        mergeSort(right)
        i = j = k = 0
        while i < len(left) and j < len(right):
            if left[i] < right[j]:
                L[k] = left[i]
                i += 1
            else:
                L[k] = right[j]
                j += 1
            k += 1
        while i < len(left):
            L[k] = left[i]
            i += 1
            k += 1
        while j < len(right):
            L[k] = right[j]
            j += 1
            k += 1


@timeIt
def selectionSort(L):
    for fillslot in range(len(L) - 1, 0, -1):
        maxpos = 0
        for location in range(1, fillslot + 1):
            if L[location] > L[maxpos]:
                maxpos = location
        temp = L[fillslot]
        L[fillslot] = L[maxpos]
        L[maxpos] = temp


randomList = random.sample(range(10000), 10000)
mergeSort(randomList.copy())
selectionSort(randomList.copy())

输出:

[...] truncated
function [mergeSort] finished in 7 ms
function [mergeSort] finished in 15 ms
function [mergeSort] finished in 33 ms
function [mergeSort] finished in 68 ms
function [selectionSort] finished in 2049 ms

【问题讨论】:

  • 您可以编写一个专用于调用 mergeSort 的函数,例如 mergeSortObserver 并用您的装饰器装饰它。由于这个特殊函数只会被调用一次,你会得到想要的行为。

标签: python function recursion time decorator


【解决方案1】:

您可以在包装函数上设置一个属性(在示例中为_entered)作为标志,这样如果设置了该属性,它就可以知道它在递归调用中:

def timeIt(func):
    @functools.wraps(func)
    def newfunc(*args, **kwargs):
        if not hasattr(newfunc, '_entered'): # enter only if _entered is not set
            newfunc._entered = True # set _entered
            startTime = time.time()
            func(*args, **kwargs)
            elapsedTime = time.time() - startTime
            print('function [{}] finished in {} ms'.format(
                func.__name__, int(elapsedTime * 1000)))
            del newfunc._entered # remove _entered
    return newfunc

【讨论】:

    【解决方案2】:

    你可以用另一个函数来包装它...

    import random
    import functools
    import time
    
    
    def timeIt(func):
        @functools.wraps(func)
        def newfunc(*args, **kwargs):
            startTime = time.time()
            func(*args, **kwargs)
            elapsedTime = time.time() - startTime
            print('function [{}] finished in {} ms'.format(
                func.__name__, int(elapsedTime * 1000)))
        return newfunc
    
    
    
    def mergeSort(L):
        if len(L) > 1:
            mid = len(L) // 2
            left = L[:mid]
            right = L[mid:]
            mergeSort(left)
            mergeSort(right)
            i = j = k = 0
            while i < len(left) and j < len(right):
                if left[i] < right[j]:
                    L[k] = left[i]
                    i += 1
                else:
                    L[k] = right[j]
                    j += 1
                k += 1
            while i < len(left):
                L[k] = left[i]
                i += 1
                k += 1
            while j < len(right):
                L[k] = right[j]
                j += 1
                k += 1
    
    
    
    def selectionSort(L):
        for fillslot in range(len(L) - 1, 0, -1):
            maxpos = 0
            for location in range(1, fillslot + 1):
                if L[location] > L[maxpos]:
                    maxpos = location
            temp = L[fillslot]
            L[fillslot] = L[maxpos]
            L[maxpos] = temp
    
    
    @timeIt
    def timedSelectionSort(L):
        selectionSort(L)
    
    @timeIt
    def timedMergeSort(L):
        mergeSort(L)
    
    
    randomList = random.sample(range(10000), 10000)
    timedSelectionSort(randomList.copy())
    timedMergeSort(randomList.copy())
    

    【讨论】:

      猜你喜欢
      • 2022-01-01
      • 2019-04-13
      • 2015-06-16
      • 2020-01-05
      • 2020-05-20
      • 1970-01-01
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多