热交换python代码(duck类型函数?)

时间:2010-08-07 23:46:18

标签: 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)

我今天意识到这是一个坏主意,例如,如果我想从顶部或底部更改某些内容,我需要编写一个shell脚本来执行此操作。 (这不是那么难,它看起来似乎是非常糟糕的代码)。

所以我想做的是,有一个外部python脚本是这样的:

Top piece of code
Dynamic function that calls the middle piece of code (based on a parameter)
Bottom piece of code

然后文件夹中的每个其他python文件都可以简单地作为中间代码。但是,普通的模块在这里不起作用(除非我弄错了),因为我会得到我需要从arguement执行的代码,这将是一个字符串,因此我不知道在运行时运行哪个函数

所以我想到了另外两个解决方案:

  1. 我可以编写一堆if语句,一个用于根据某个参数运行每个脚本。我拒绝了这一点,因为它比以前的设计更糟糕。
  2. 我可以使用:

    os.command(sys.argv [0] scriptName.py)

    会运行脚本,但调用python来调用python对我来说似乎不太优雅。

  3. 那么有没有人有任何其他想法?谢谢。

6 个答案:

答案 0 :(得分:4)

如果您将函数的名称知道为字符串,并将模块的名称作为字符串知道,那么您可以

mod = __import__(module_name)
fn = getattr(mod, fn_name)
fn()

答案 1 :(得分:4)

另一种可能的解决方案是让每个重复文件从主文件中导入功能

from topAndBottom import top, bottom
top()
# do middle stuff
bottom()

答案 2 :(得分:2)

除了已发布的几个答案之外,请考虑Template Method设计模式:制作一个抽象类,例如

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上的许多技术演讲中充分解释了这一点 - 模板方法(尽管名称可怕;-)是一个坚实的,经过充分验证的可扩展的模式[[有时太过刻板,但这正是我在那些许多技术会谈中所说的 - 而且这个问题不适用于这个特定的用例]]。

答案 3 :(得分:0)

  

然而,正常的模块在这里不起作用(除非我弄错了),因为我会得到我需要从arguement执行的代码,这将是一个字符串,因此我不知道哪个函数运行到运行时。

它可以正常工作 - 使用__import__内置,或者,如果你有非常复杂的布局,imp模块可以导入你的脚本。然后你可以通过module.__dict__[funcname]得到函数。

答案 4 :(得分:0)

导入一个模块(正如其他答案中所解释的)绝对是更清洁的方法,但如果出于某种原因无效,只要你没有做任何太奇怪的事情就可以使用{{3 }}。它基本上运行另一个文件的内容,就好像它被调用exec时包含在当前文件中一样。它是Python与许多shell中包含的source语句最接近的东西。至少应该是这样的:

exec(open(filename).read(None))

答案 5 :(得分:0)

这个怎么样?

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