2009-04-15 106 views
0

HY一切,我有以下的 “错误” 的调度员:调度蟒蛇

def _load_methods(self): 
    import os, sys, glob 
    sys.path.insert(0, 'modules\commands') 
    for c in glob.glob('modules\commands\Command*.py'): 
     if os.path.isdir(c): 
      continue 
     c = os.path.splitext(c)[0] 
     parts = c.split(os.path.sep) 
     module, name = '.'.join(parts), parts[-1:] 
     module = __import__(module, globals(), locals(), name) 
     _cmdClass = __import__(module).Command 
     for method_name in list_public_methods(_cmdClass): 
      self._methods[method_name] = getattr(_cmdClass(), method_name) 
    sys.path.pop(0) 

它产生以下错误:

导入错误:没有模块名为commands.CommandAntitheft

where命令*。 py被放入modules \ commands \文件夹中

有人可以帮助我吗?

一个可能的解决方案(它的工作原理!!!)是:

def _load_methods(self): 
    import os, sys, glob, imp 

    for file in glob.glob('modules/commands/Command*.py'): 
     if os.path.isdir(file): 
      continue 
     module = os.path.splitext(file)[0].rsplit(os.sep, 1)[1] 
     fd, filename, desc = imp.find_module(module, 
       ['./modules/commands']) 
     try: 
      _cmdClass = imp.load_module(module, fd, filename, desc).Command 
     finally: 
      fd.close() 

     for method_name in list_public_methods(_cmdClass): 
      self._methods[method_name] = getattr(_cmdClass(), method_name) 

它仍然通过bobince建议(坦克:-))的所有风险,但现在我能够在“运行”加载命令

+0

嗨@ DrFalk3n我偶然发现了你的旧问题。时代已经发生了变化,这个问题并没有真正符合当前有关什么样的问题的指导方针。你想让它保持这种方式还是自己编辑它,或者我可以继续编辑它? – Breeze 2016-07-07 11:10:50

+0

请随时改变它,thkk – DrFalk3n 2016-07-08 15:00:02

回答

1

sys.path.insert(0, 'modules\commands')

最好不要把相对路径放到sys.path中。如果当前目录在执行过程中发生更改,它会中断。

此外,如果您从不同的目录运行到脚本,它将无法工作。如果您想使其相对于脚本的位置,请使用文件

为了安全起见,还应将'\'字符转义为'\\',实际上它应该使用os.path.join()而不是依赖Windows路径规则。

sys.path.insert(0, os.path.abspath(os.path.join(__file__, 'modules'))) 

sys.path.pop(0)

危险。如果另一个导入的脚本已经使用了sys.path(可能),那么你就会把错误的路径关闭。重新加载自己的模块也会中断。最好离开它所在的道路。

module, name = '.'.join(parts), parts[-1:]

记住你的路径包含段“模块”。所以你有效尝试:

import modules.commands.CommandSomething 

但由于“modules.commands”已经在你的路径添加到搜索你真正想要的只是:

import CommandSomething 

__import__(module, globals(), locals(), name)

又“ fromlist'是一个列表,所以如果你真的想把'CommandSomething'写入你的局部变量,它应该是'[name]'。 (你几乎肯定不希望这样,离开fromlist里是空的。)

_cmdClass = __import__(module).Command

是啊,这是行不通的,模块是一个模块对象,__import__想要一个模块名称。你已经有了模块对象;为什么不只是“module.Command”?

我对这一切的反应很简单:魔法太多

你让自己过于困难,并通过混淆导入系统的内部来创造很多潜在的问题和脆弱性。即使对于有经验的Python程序员来说,这也是棘手的问题。

你肯定会更好地使用明确导入的普通旧Python模块。对命令列表进行硬编码确实不是很大的困难;让你的所有命令的封装,__init__.py说:

__all__= ['ThisCommand', 'ThatCommand', 'TheOtherCommand'] 

可重复一次的文件名,但比一个神奇的过量更简单,更可靠。

1

你真的需要导入东西作为模块吗?如果您只是从文件系统中的任意位置加载代码,那么您可以使用execfile而不是模块路径等。

即。

for file in glob.glob('modules/commands/Command*.py'): 
    if os.path.isdir(file): 
     continue 

    moddict={} 
    execfile(file, moddict) 
    _cmdClass = moddict['Command'] 
    ...