python项目中不同文件夹py源文件之间如何相互调用,下面将以实际例子给出两种解决方
案:一种是Python import中相对路径的问题;另一种是利用python的importlib标准库模块支持传递字符串来导入模块
(1)、解决Python import中相对路径的问题
例子假设:
创建一个以AB文件夹的python项目,里面的源文件如下所示,其中“__init__.py”为定义模块的标配。
from AB.B import B from AB import AB class AClass(): def __init__(self): pass def print_a(self,name): print "A.print_a()",name if __name__=="__main__": obi_AClass=AClass() obi_AClass.print_a(" from A.A.py") obj_BClass=B.BClass() obj_BClass.print_b(" from A.A.py") obj_ABClass=AB.ABClass() obj_ABClass.print_ab(" from A.A.py")
class BClass(): def __init__(self): pass def print_b(self,name): print "B.print_b()",name
from B import B class ABClass(): def __init__(self): pass def print_ab(self,name): print "AB.print_ab()",name if __name__=="__main__": obj_ABclass=ABClass() obj_ABclass.print_ab(" from AB.AB.py") obj_Bclass=B.BClass() obj_Bclass.print_b(" from AB.AB.py")
Python将importlib作为标准库提供。它旨在提供Python import语法和(__import__()函数)的实现。另外,importlib提供了开发者可以创建自己的对象(即importer)来处理导入过程。
这个模块比较复杂,文中我们主要探讨如下主题:
1)、动态导入 (适用于python2.7及以上)
2)、检查模块是否可以导入(适用于python 3.x以上)
3)、从源文件导入(适用于python 3.x以上)
1、动态导入
importlib模块支持传递字符串来导入模块。我们先来创建一些简单模块一遍演示。我们在模块里提供了相同接口,通过打印它们自身名字来区分。我们分别创建了foo.py和bar.py,bar.py代码如下:
def main():
print(__name__)
print "from bar.py"
def main():
print(__name__)
print "from foo.py"
#importer
import importlib
def dynamic_import(module):
return importlib.import_module(module)
if __name__ == "__main__":
module = dynamic_import('foo')
module.main()
module2 = dynamic_import('bar')
module2.main()
这里我们导入importlib模块,并创建了一个非常简单的函数dynamic_import。这个函数直接就调用了importlib的import_module方法,并将要导入的模块字符串传递作为参数,最后返回其结果。然后在主入口中我们分别调用了各自的main方法,将打印出各自的name.
foo
from foo.py
bar
from bar.py
也许你很少会代码这么做,不过在你需要试用字符串作为导入路径的话,那么importlib就有用途了。
2、模块导入检查
Python有个众所周知的代码风格EAFP: Easier to ask forgiveness than permission.它所代表的意思就是总是先确保事物存在(例如字典中的键)以及在犯错时捕获。如果我们在导入前想检查是否这个模块存在而不是靠猜。 使用mportlib就能实现。
import importlib.util
def check_module(module_name):
"""
Checks if module can be imported without actually
importing it
"""
module_spec = importlib.util.find_spec(module_name)
if module_spec is None:
print("Module: {} not found".format(module_name))
return None
else:
print("Module: {} can be imported".format(module_name))
return module_spec
def import_module_from_spec(module_spec):
"""
Import the module via the passed in module specification
Returns the newly imported module
"""
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
return module
if __name__ == '__main__':
module_spec = check_module('fake_module')
module_spec = check_module('collections')
if module_spec:
module = import_module_from_spec(module_spec)
print(dir(module))
这里我导入了importlib的子模块util。check_module里面调用find_spec方法, 传递该模块字符串作为参数。当我们分别传入了一个不存在和存在的Python模块。你可以看到当你传入不存在的模块时,find_spec函数将返回 None,在我们代码里就会打印提示。如果存在我们将返回模块的specification。
我们可以通过该模块的specification来实际导入该模块。或者你直接将字符串作为参数调用import_module函数。不过我这里也学习如何试用模块specification方式导入。看看import_module_from_spec函数。它接受check_module提供的模块specification作为参数。然后我们将它传递给了module_from_spec函数,它将返回导入模块。Python文档推荐导入后然后执行模块,所以接下来我们试用exec_module函数执行。最后我们使用dir来确保得到预期模块。
3、从源代码导入
importlib的子模块有个很好用的技巧我想提提。你可以使用util通过模块的名字和路径来导入模块。
import importlib.util
def import_source(module_name):
module_file_path = module_name.__file__
module_name = module_name.__name__
module_spec = importlib.util.spec_from_file_location(
module_name, module_file_pat)
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
print(dir((module)))
msg = 'The {module_name} module has the following methods {methods}'
print(msg.format(module_name=module_name, methods=dir(module)))
if __name__ == "__main__":
import logging
import_source(logging)
在上面的代码中,我们实际导入logging模块,并将模块传递给了import_source函数。这样我们就可以通过导入的模块获取到实际的路 径和名字。然后我们将信息传递给sec_from_file_location函数,它将返回模块的specification。也了这个我们就可以在前 面那样直接通过importlib导入了。
如果你想自定义importer或者loader,那么你可以通过官方文档或者源代码了解更多。
参考: http://www.cnblogs.com/meishandehaizi/p/5863233.html