Python:在给定两个预先生成的函数的情况下,如何有效地选择要使用的函数?

2024-10-03 04:35:44 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个带有两个函数的模块myfunctions

def functionA():
    return'Function A chosen.'

def functionB():
    return 'Function B chosen.'

然后,我有一个模块silly,它对以下函数执行一些操作:

def sillyprinter():
    print chosen_function
    print chosen_function()

然后,在我的主要剧本中,我有:

import myfunctions
import silly

class FunctionChooser():
    def __init__(function_choice="A"):
        self.choose_function_given_choice(function_choice)

    def do_something_many_times(self):
        for i in range(1000):
            silly.sillyprinter()

FunctionChooser的思想是用一些用户给定的信息来初始化它,这些信息与我想从myfunctions使用哪个函数(A或B)有关。然后,在做出这个选择之后,用户可以调用do_something_many_times,这将使用另一个模块,该模块将多次使用从myfunctions中选择的函数。你知道吗

为了提高效率,我想避免以下情况:

1)一次又一次地选择要使用的函数——所以我想做一次选择(在初始化期间),然后以某种方式“保存”它。此要求取消了以下设计的资格:

def sillyprinter(chosen_function):
    print chosen_function
    print chosen_function()

# =================================

class FunctionChooser():
    def __init__(function_choice="A"):
        self.function_choice = function_choice

    def choose_function_given_choice(self):
        if self.function_choice == "A":
            return myfunctions.functionA
        elif self.function_choice == "B":
            return myfunctions.functionB

    def do_something_many_times(self):
        for i in range(1000):
            silly.silly_printer(self.choose_function_given_choice())

2)存储我想选择作为类属性的函数since ^{} calls are expensive, and the use case is numerical。这一要求取消了如下设计的资格:

def sillyprinter(chosen_function):
    print chosen_function
    print chosen_function()

# =================================

class FunctionChooser():
    def __init__(function_choice="A"):
        self.function_choice = function_choice

    def choose_function_given_choice(self):
        if self.function_choice == "A":
            self.chosen_function = myfunctions.functionA
        elif self.function_choice == "B":
            self.chosen_function = myfunctions.functionB

    def do_something_many_times(self):
        for i in range(1000):
            silly.silly_printer(self.chosen_function)

我目前的想法是:

def sillyprinter(chosen_function):
    print chosen_function
    print chosen_function()

# =================================

class FunctionChooser():
    def __init__(function_choice="A"):
        self.function_choice = function_choice

    def choose_function_given_choice(self):
        if self.function_choice == "A":
            self.chosen_function = myfunctions.functionA
        elif self.function_choice == "B":
            self.chosen_function = myfunctions.functionB

    def do_something_many_times(self):
        chosen_function = self.chosen_function
        for i in range(1000):
            silly.silly_printer(chosen_function)

它只是与我在2)中取消的设计稍有不同,因为它只进行一次self调用,然后将该函数存储为局部变量。你知道吗

Is this the best way to design such "function choice" in Python, given my requirements? (see below)

编辑:我想我应该把要求弄清楚,这样问题就不那么笼统了

  1. “函数选择字符串”不必是字符串——它可以是为某种函数选择编码的任何变量。你知道吗
  2. 我想避免self.访问调用(但通常可能是.访问调用?)由于numba使用访问调用优化代码的问题:Design heuristics for writing Python classes that interact with `scipy.integrate.odeint`?
  3. “function choice”变量只给出一次,因此我们可以认为它实际上是一个常量。你知道吗

Tags: 函数selfdeffunctiondosomethinggivenprint
2条回答

基本答案是,这三个选项中的任何一个都可能是“最佳”的,具体取决于具体情况。但是您所选择的选项之间的差异是微妙的,并且在大多数情况下不太可能显著影响性能。与其在这里担心效率,不如担心概念上的优雅。然后,如果你需要效率,优化。你知道吗

我可以想象,从概念上讲,这三种选择中的任何一种都是可取的。你知道吗

  1. 假设函数的选择取决于一个经常变化的值。您必须经常检查它的状态,那么存储它会有什么好处呢?只要每次都查一下就更有意义了。在这种情况下,(1)是最好的选择。

  2. 假设函数的选择不会基于一个经常改变的值,或者一个易于“反转控制”的值(即关注变量的代码也知道如何改变函数的选择)。除非您有压倒一切的理由担心单个.访问的额外开销,否则只需将其存储为属性。(请注意,在self中查找属性的成本并不比在其他对象中查找属性的成本高。操作完全相同;self没有什么特别之处在这种情况下,(2)是最好的选择。

  3. 假设函数的选择不会基于经常更改的值,而是函数本身会经常被调用。此外,您确信.访问正在减慢代码的速度,因为您已经完成了严格的测试。然后将.访问的结果缓存在局部变量中是有意义的,如选项(3)所示。(但请注意,在选项(3)中,您仍然在使用另一个.操作,该操作也应该被缓存,就像在Ignacio的回答中一样。)但是要小心过早的优化!每一个局部变量都会给您和您的开发人员带来额外的认知负荷,您必须确保这是值得的。只有如果你真的做过测试的话,才选择这个选项,这会造成显著的速度差异。

最后一点注意:在您的示例代码中还有一些额外的复杂性,我假设这些复杂性应该是为了唤起复杂性,而不是在这种特殊情况下的特定目的。例如,给定您实际发布的代码,choose_function_given_choice函数是非常无用的。但我想你已经知道了。不过,要重申显而易见的一点,你应该以最简单的方式实现这一切。你知道吗

不,Python中的函数是一级对象;将它们视为一级对象。你知道吗

class FunctionChooser():
    def __init__(function_choice=myfunctions.functionA):
        self.function_choice = function_choice

    def do_something_many_times(self):
        chosen_function = self.chosen_function
        printer = silly.silly_printer
        for i in range(1000):
            printer(chosen_function)

相关问题 更多 >