如何在完整路径下加载Python模块?请注意,该文件可以位于文件系统中的任何位置,因为它是一个配置选项.
我正在编写一个Python应用程序,它将命令作为参数,例如:
$ python myapp.py command1
Run Code Online (Sandbox Code Playgroud)
我希望应用程序是可扩展的,即能够添加实现新命令的新模块,而无需更改主应用程序源.树看起来像:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Run Code Online (Sandbox Code Playgroud)
所以我希望应用程序在运行时找到可用的命令模块并执行适当的命令模块.
Python定义了一个__import__函数,它接受一个模块名称的字符串:
__import __(name,globals = None,locals = None,fromlist =(),level = 0)
该函数导入模块名称,可能使用给定的全局变量和局部变量来确定如何解释包上下文中的名称.fromlist给出了应该从name给出的模块导入的对象或子模块的名称.
所以目前我有类似的东西:
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
Run Code Online (Sandbox Code Playgroud)
这很好用,我只是想知道是否可能有更惯用的方法来完成我们正在使用此代码.
请注意,我特别不想使用鸡蛋或扩展点.这不是一个开源项目,我不希望有"插件".重点是简化主应用程序代码,并在每次添加新命令模块时无需修改它.
我使用的是Python 3.5.1.我在这里阅读了文档和包部分:https://docs.python.org/3/tutorial/modules.html#packages
现在,我有以下结构:
/home/wujek/Playground/a/b/module.py
Run Code Online (Sandbox Code Playgroud)
module.py:
class Foo:
def __init__(self):
print('initializing Foo')
Run Code Online (Sandbox Code Playgroud)
现在,在/home/wujek/Playground:
~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>
Run Code Online (Sandbox Code Playgroud)
同样,现在在家里,超级文件夹Playground:
~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>
Run Code Online (Sandbox Code Playgroud)
实际上,我可以做各种各样的事情:
~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b
Run Code Online (Sandbox Code Playgroud)
为什么这样做?我虽然有被需要的__init__.py文件(空的都可以)两种a,并b为module.py要导入的时候Python的路径指向Playground文件夹?
这似乎已经从Python 2.7改变了:
~ $ PYTHONPATH=Playground …Run Code Online (Sandbox Code Playgroud) 根据官方文档,os.path是一个模块.那么,导入它的首选方式是什么?
# Should I always import it explicitly?
import os.path
Run Code Online (Sandbox Code Playgroud)
要么...
# Is importing os enough?
import os
Run Code Online (Sandbox Code Playgroud)
请不要回答" os为我导入作品".我知道,它现在也适用于我(从Python 2.6开始).我想知道的是关于这个问题的任何官方建议.因此,如果您回答此问题,请发布您的推荐信.
可能重复:
Python中的动态模块导入
我打算在不久的某个时候制作一套文件,组织它的最好方法是有一个列表,该列表将位于文件的最顶层,之后将会出现一些荒谬的代码来处理该列表控制的内容及其运行方式.我只想写一次所说的列表,并且列表是这种格式的文件夹和文件名列表:
[(folder/filename, bool, bool, int), (folder/filename, bool, bool, int)]
Run Code Online (Sandbox Code Playgroud)
如你所见,folder/filename是相同的(有点).文件名是最后的文件夹名称.py,但进行导入XXX你不需要导入XXX.py,所以我没有看到这导致问题.
我面临的问题是使用这种方法导入...
for (testName, auto, hardware, bit) in testList:
print(testName)
paths = "\\" + testName
print paths
addpath(paths)
sys.modules[testName] = testName # One of a few options I've seen suggested on the net
print("Path Added")
test = testName + ".Helloworld()"
eval(test)
Run Code Online (Sandbox Code Playgroud)
因此,对于我所拥有的每个测试,打印名称,组装包含path("\\testName")的字符串,对于此示例,打印测试路径,然后将路径添加到list(sys.path.append(path)),然后打印以确认它发生,然后组装一个将由eval测试主模块执行的字符串,并最终对其进行评估.
如您所见,我目前必须在顶部有一个导入列表.我不能简单地做导入testName(内容testName是我想导入的模块的名称),因为它会尝试查找一个名为的模块testName,而不是一个名为内容的模块testName.
我已经看到了一些这样做的例子,但在我的情况下找不到哪些工作.如果有人可以真正抛出一大堆代码来完成那将是美妙的.
我还要求我没有挂起,绘制,也没有使用eval,它在一个非常受控制的环境中使用(它循环的列表在.py文件中,所以没有"最终用户"应该一塌糊涂).
我知道我可以用来importlib通过字符串导入模块.如何import *使用此库重新创建功能?基本上,我想要这样的东西:
importlib.import_module('path.to.module', '*')
Run Code Online (Sandbox Code Playgroud)
我没有对导入的属性进行名称间隔的原因是故意的.
我的代码是这样的:
for module in ["ffmpy","os","sys"]:
try:
__import__(module)
except:
print("Can't import ["+module+"]")
Run Code Online (Sandbox Code Playgroud)
所以,我想全局导入它,但它似乎没有这样做.在这段代码之后,我有sys.path.insert(0, r"C:\Users\david\Desktop\scripts"),并且python控制台告诉我:NameError: name 'sys' is not defined.我不知道我做错了什么,但你希望这样做.
编辑:这个问题不重复,因为我不只是想从字符串导入,而是从for循环中执行.我基本上想要从一个循环中的字符串全局导入.