“预处理”Python 函数,以避免条件逻辑的过度评估

问题描述 投票:0回答:1

我正在编写一些 Python 代码,其中包含带有两组参数的函数。每次调用该函数时,第一组参数都会不同。对于大组函数调用,第二组参数将是相同的(例如,这些参数每 10000 次函数评估就会改变)。我希望以这样的方式编写此函数:每当第二组参数的值发生变化时,条件逻辑仅运行一次。我已经包含了一些我认为可能有效的代码,但是在使用时间模块进行一些测试之后,改进似乎很小。这段代码实际上是在执行我所描述的操作吗?如果没有,Python 有没有办法做到这一点?

def preprocessor (parameter_array):
    
    # example parameters
    condition = parameter_array[0]
    index = parameter_array[1]

    def f (x_array):

        result = 0

        if (condition):
            result += x_array[index] ** 2
        else:
            result += x_array[index] - 5

        #.
        #.
        #.

        return result

    return f


# define some test parameters
test_parameters = [True, 1]

# run the function 100000 times with these parameters
function = preprocessor(test_parameters)

sum = 0

for i in range(100000):

    sum += function([i, i])

print(sum)

我的希望是,以这种方式编写的 if 语句仅在我调用

preprocessor
函数时才被评估。因此,它加快了 for 循环的计算速度,其中仅 x 值发生变化。运行时间约为 0.024 秒,而控件运行时间约为 0.028 秒。我还包含了用于下面控件的代码(为了便于阅读,所有内容都没有时间模块)。

def f (x_array, parameter_array):
        
    # example parameters
    condition = parameter_array[0]
    index = parameter_array[1]

    result = 0

    if (condition):
        result += x_array[index] ** 2
    else:
        result += x_array[index] - 5

    #.
    #.
    #.

    return result


# define some test parameters
test_parameters = [True, 1]

# run the function 100000 times without using the preprocessed function

sum = 0

for i in range(100000):

    sum += f([i, i], test_parameters)

print(sum)
python python-3.x function performance preprocessor
1个回答
0
投票

答案:

是的,它正在做你认为它正在做的事情。一个简单的判断方法就是添加一些打印语句。

def initialize(initialState):
    state = initialState
    print(f"I am executed on initialization: {initialState}")
    def f(increment): 
        nonlocal state
        print(f"I am incrementing {state} by {increment}")
        state = state = increment
    
    return f

fun = initialize(10)
fun(5)
fun(20)

输出

I am executed on initialization: 10
I am incrementing 10 by 5
I am incrementing 5 by 20

旁白:

您的示例可能过于简单,但您提取的逻辑非常简单。你不会获得那么多的速度。我不确定条件和返回之间是否有额外的代码,但是声明返回值然后根据条件的结果递增它是不必要的。

在这里,我将您的方法与两种不同的简化进行了比较,并且都实现了加速。 Python确实是一种奇怪的语言。我所知道的每种编译语言都能够在使用三元时消除分支指令。我预计三元方法是最快的。

import timeit

def approach1(): 
    def preprocessor (parameter_array):
        condition = parameter_array[0]
        index = parameter_array[1]
        return lambda x_array: x_array[index] ** 2 if condition else x_array[index] - 5
    test_parameters = [True, 1]
    function = preprocessor(test_parameters)
    sum = 0
    for i in range(100000):
        sum += function([i, i])
    
def approach2():
    def preprocessor (parameter_array):
        condition = parameter_array[0]
        index = parameter_array[1]
        def f (x_array):
            result = 0
            if (condition):
                result += x_array[index] ** 2
            else:
                result += x_array[index] - 5
            return result
        return f
    
    test_parameters = [True, 1]
    function = preprocessor(test_parameters)
    sum = 0
    for i in range(100000):
        sum += function([i, i])

def approach3():
    def preprocessor (parameter_array):
        condition = parameter_array[0]
        index = parameter_array[1]
        def f (x_array):
            if (condition):
                return x_array[index] ** 2
            return x_array[index] - 5
        return f
    test_parameters = [True, 1]
    function = preprocessor(test_parameters)
    sum = 0
    for i in range(100000):
        sum += function([i, i])

n = 100
print(timeit.timeit(approach1, number=n))
print(timeit.timeit(approach2, number=n))
print(timeit.timeit(approach3, number=n))

输出

0.8117037120027817
0.9467067930017947
0.8014805819984758

附注

虽然这些类型的优化可能很有趣并且可以帮助您了解语言的性能特征,但您的时间最好花在优化诸如您正在使用的算法之类的事情上。如果您真的需要性能,Python 不适合您。

© www.soinside.com 2019 - 2024. All rights reserved.