热插拔python代码(duck类型函数?)
我想这件事想得太久了,还不知道,也许你们中的一些人能帮上忙 我有一个python脚本文件夹,所有脚本都有相同的主体(字面上,我是从shell脚本生成的),但有一个块与所有脚本不同。换言之:热插拔python代码(duck类型函数?),python,python-3.x,blender,Python,Python 3.x,Blender,我想这件事想得太久了,还不知道,也许你们中的一些人能帮上忙 我有一个python脚本文件夹,所有脚本都有相同的主体(字面上,我是从shell脚本生成的),但有一个块与所有脚本不同。换言之: Top piece of code (always the same) Middle piece of code (changes from file to file) Bottom piece of code (always the same) 我今天意识到这是一个坏主意,例如,如果我想从顶部或底部更改某
Top piece of code (always the same)
Middle piece of code (changes from file to file)
Bottom piece of code (always the same)
我今天意识到这是一个坏主意,例如,如果我想从顶部或底部更改某些内容,我需要编写一个shell脚本来完成。(并不是说这很难,只是看起来它的代码非常糟糕)
所以我想做的是,有一个外部python脚本,如下所示:
Top piece of code
Dynamic function that calls the middle piece of code (based on a parameter)
Bottom piece of code
然后,文件夹中的每个其他python文件都可以是中间的代码段。然而,普通模块在这里不起作用(除非我弄错了),因为我将从参数中获得需要执行的代码,这将是一个字符串,因此直到运行时我才知道要运行哪个函数
所以我又想出了两个解决方案:
那么有人有其他想法吗?谢谢。如果您知道函数名是字符串,模块名是字符串,那么您可以这样做
mod = __import__(module_name)
fn = getattr(mod, fn_name)
fn()
然而,普通模块在这里不起作用(除非我弄错了),因为我将从参数中获得需要执行的代码,这将是一个字符串,因此直到运行时我才知道要运行哪个函数
它将很好地工作-使用内置的,或者,如果你有非常复杂的布局,模块来导入你的脚本。然后你可以通过模块来获得函数。例如,导入一个模块(如其他答案中所解释的)肯定是一种更简洁的方法,但是如果出于某种原因这不起作用,只要你没有做任何太奇怪的事情,你就可以使用它。它基本上运行另一个文件的内容,就好像它在调用exec
时包含在当前文件中一样。它是Python最接近于许多shell中包含的源语句的东西。作为最低要求,类似这样的方法应该有效:
exec(open(filename).read(None))
另一种可能的解决方案是让每个重复文件从主文件导入功能
from topAndBottom import top, bottom
top()
# do middle stuff
bottom()
这个怎么样
function do_thing_one():
pass
function do_thing_two():
pass
dispatch = { "one" : do_thing_one,
"two" : do_thing_two,
}
# do something to get your string from the command line (optparse, argv, whatever)
# and put it in variable "mystring"
# do top thing
f = dispatch[mystring]
f()
# do bottom thing
除了已经发布的几个答案外,还可以考虑设计模式:制作一个抽象类,如
class Base(object):
def top(self): ...
def bottom(self): ...
def middle(self): raise NotImplementedError
def doit(self):
self.top()
self.middle()
self.bottom()
然后,每个可插入模块生成一个类,该类继承自该Base
,并且必须用相关代码覆盖middle
对于这种简单的情况,可能并不保证(您仍然需要导入正确的模块来实例化其类并在其上调用doit
),但仍然值得记住(以及它的许多Pythonic变体,我已经在youtube上的许多技术讲座中详细解释了这一点)对于“可插拔部件”的数量或复杂性不断增长的情况,模板方法(尽管其名称可怕;-)是一种可靠、经过充分验证且高度可扩展的模式[[有时有点过于僵化,但这正是我在许多技术讲座中所提到的——这个问题不适用于这个特定的用例]].在创建此脚本之前,您试图解决哪个问题?嗯……好吧,虽然脚本将与其他函数放在同一个文件夹中,但我想init.py文件不会有太大问题。虽然所有脚本所在的文件夹都称为python,但我想知道这是否会成为一个问题……只要目录位于sys.path
中,就不应该是一个问题。啊,是的,它工作得很好。我所做的是将所有文件更改为只有一个名为func()的函数,然后使用mod=\uuuu import\uuuu(file\u name\u减号\u py)获得模块名,并调用mod.func(),谢谢。@Leif Andersen,制作一个模块函数接口,每个可用的中间模块都应该实现,他们都应该定义一个名为process
的函数。您可以基于约定或配置(在这种情况下,您可能需要添加一个配置文件)来创建解决方案。嗯……我认为这行不通,也许我没有说清楚。top()部分中的代码将设置pyunit测试用例,中间部分将在测试用例中进行测试,而bottom()函数将完成测试用例。(如果这不是在一个班的中间,我会同意这是最好的解决方案)。@ LeIF不熟悉PyUnbe,但是你能把中间部分作为一个函数在适当的上下文中调用吗?如果它变得太复杂,最好使用\uuuuu import\uuuuu
解决方案,我将每个(中间的东西)转换成一个函数(只给每个文件提供该函数),然后使用uu import\uuuu(修改的参数名称)导入文件,并调用该类中的函数。这可能涉及将所有函数放在一个文件中,或者导入每个运行时的每个模块。也许它比使用_import__()(我最终使用了它)更干净,谢谢你,下次我需要做类似的事情时,我会记住它。@Leif,正如我提到的,你的具体问题可能很简单,一个没有类、只有函数的解决方案可以很好地工作(一般来说,使用最简单且效果良好的解决方案是一个好主意;-),但我很高兴您将来喜欢模板方法的想法。