我有一个看似简单的Python代码设计问题,我还没有找到任何优雅的解决方案。我有一组模块(下面的例子中有两个)定义了相同名称的函数,它们使用不同的算法计算相同的东西:
algorithm_a.py:
def compute_1(x):
# do some computation
return (x+1.)**2
def compute_2(x):
# do some other computation
# etc
algorithm_b.py:
def compute_1(x):
# do same computation in another way
return x*x + 2.0*x + 1.0
def compute_2(x):
# do some other computation in another way
# etc
这两个模块大约有10个功能,但未来这个数字可能会增长。
在第三个模块中,我定义的函数不知道如何执行计算的细节,即它们只关心获得正确的答案。用户的界面由类提供。总而言之,第三个模块看起来类似于:
simulation.py:
import XXX as algo #????
def do_computation_1(x):
v1 = algo.compute_1(x)
v2 = algo.compute_2(x)
# Do some computations using v1, v2
return result
def do_computation_2(x):
return algo.compute_2(x)
# etc etc
class Simulation(object):
def __init__(self, method):
# Do some magic here so that
# if method == "A":
# algo = algorithm_a
# if method == "B"
# algo = algorithm_b
def run(self, x):
do_computation_1(x)
do_computation_2(x)
如何在do_computation()中加载和应用正确的模块,以取决于提供给类的方法参数?
请注意,do_computation函数需要保留在Simulation类之外。
结论:以下@BrenBarn的评论总结了可用的选项。谢谢大家的帮助!
答案 0 :(得分:1)
更好的方法是实际保存(或传递)您想要使用的功能。例如。
import algorithm_a
import algorithm_b
class Simulation(object):
def __init__(self, method):
# Do some magic here so that
if method == "A":
self.compute_func = algorithm_a.compute
if method == "B"
self.compute_func = algorithm_b.compute
def run(self, x):
self.compute_func(x)
如果你真的必须有你的外部def do_computation(x)
功能,你可以传递你想用作参数的算法
def do_computation(x, compute):
return compute(x)
class Simulation(object):
def __init__(self, method):
# Do some magic here so that
if method == "A":
self.compute_func = algorithm_a.compute
if method == "B"
self.compute_func = algorithm_b.compute
def run(self, x):
do_computation(x, self.compute_func)
答案 1 :(得分:0)
通过构建代码的方式,您无法根据传递给类的参数进行导入。 Python文件从上到下执行。您的导入发生在类定义之前,因此在定义类时,导入已经发生。 (并且你不会传递method
,直到你实例化这个类,这将会更晚。)
如果可以导入两个模块并且您只想使用指定的模块,那么您几乎可以按照字面意义完成您在评论中所写的内容:
import algorithm_a
import algorithm_b
class Simulation(object):
def __init__(self, method):
if method == "A":
self.algo = algorithm_a
if method == "B"
self.algo = algorithm_b
def do_computation(self, x):
return self.algo.compute(x)
def run(self, x):
self.do_computation(x)
(我在这里使do_computation
成为了类的一个方法。如果它的行为是由传递给类的参数决定的,那么将它作为一个单独的函数是没有意义的。)< / p>
如果模块的实际导入速度很慢,您可以有条件地导入一个模块或者如Reblochon的答案中所示的那样。但是,要执行此操作,必须将导入放在类中。如果您要通过类似Simulation("A")
的内容指定算法,则无法确定在执行import simulation
时要执行的导入,因为您还没有指定当时的算法;你必须等到实际打电话给Simulation("A")
。 (如果导入速度很慢,这将导致此时减速,这可能是不可取的。)
编辑:如果你真的需要do_computation
因为Numba而成为一个全局函数,你可以通过设置一个全局变量来解决它。将__init__
更改为:
def __init__(self, method):
global algo
if method == "A":
algo = algorithm_a
if method == "B"
algo = algorithm_b
制作一个像这样的全局do_computation
函数:
def do_computation(x):
return algo.compute(x)
这将更加令人困惑,因为每次创建新的Simulation
时,它都会改变全局行为,即使对于以前创建的模拟也是如此。但如果你不能同时使用不同的算法创建多个模拟,那应该没问题。