python项目中不同文件夹py源文件之间如何相互调用--Python import中相对路径的问题

本文介绍Python项目中不同文件夹下的.py文件如何相互调用。包括解决Python import相对路径问题的方法,以及利用importlib模块动态导入和检查模块是否可以导入的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

python项目中不同文件夹py源文件之间如何相互调用,下面将以实际例子给出两种解决方

案:一种是Python import中相对路径的问题;另一种是利用python的importlib标准库模块支持传递字符串来导入模块

(1)、解决Python import中相对路径的问题

例子假设:

创建一个以AB文件夹的python项目,里面的源文件如下所示,其中“__init__.py”为定义模块的标配。

AB文件夹包含A文件夹和B文件夹
A文件又有个AA.py  和__init__.py
B文件夹有个BB.py  和 __init__.py
AB文件夹下还有一个AB.py 和 __init__.py
求怎么相互引用
下面将具体展示各个文件夹的内容,感兴趣的读者可以参照有效解决python import的相对路径问题:
1. AA.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")
2. BB.py
class BClass():
    def __init__(self):
        pass
    def print_b(self,name):
        print "B.print_b()",name
3. AB.py
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")

4. __init__.py
其中“__init__.py”为定义模块的标配,为空。
(二)、利用python的importlib模块支持传递字符串来导入模块

    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"
foo.py代码如下:
def main():
    print(__name__)
    print "from foo.py"
现在我们尽需要使用importlib导入它们。我们来看看代码是如何实现的,确保该代码在刚才创建的两个文件的相同目录下。
#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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值