zoukankan      html  css  js  c++  java
  • python项目内import其他内部package的模块的正确方法

    本文主要介绍如何在一个python项目中,优雅的实现项目内各个package的模块(module)之间的相互引用。

    之所以写这篇文章,是因为网上流传的各种奇技淫巧简直五花八门(包括stackoverflow等知名社区),极易误导对python的import机制不熟悉的人。比如我就曾一度因为找不到优雅的import方式,而认为python是一门愚蠢的语言。所以,我把近一上午的学习结果总结出来,希望大家不要误入歧途。

    本文参考了如下两篇博客: 
    habnab关于python package的精彩总结:地址点我 
    Jean-Paul Calderone关于python项目结构的建议:地址点我

    demo project

    本文以一个demo project为例,来介绍python的包管理机制。

    这个demo project我放到github上了:地址点我

    其中,项目根目录有三个文件夹:

    • data:存放项目数据
    • doc:存放项目文档
    • package:一个demo python package

    其中,package中的文件结构如下图: 
    项目结构

    python package

    基础知识

    当你import的时候,python只会在sys.path这个变量(一个list,你可以print出来看)里面的路径中找可能匹配的package和module。

    而一个package跟一个普通文件夹的区别在于,package的文件夹中多了一个__init__.py文件。换句话说,如果你在某个文件夹中添加了一个__init__.py文件,则python就认为这个文件夹是一个package。

    __init__.py文件可以是空的(也推荐者这么做),它只是告诉python当前文件夹是一个package。当然,也可以在里面添加一些代码,这些代码会在import这个包的时候运行。

    所以,请确保你要import的文件所在的文件夹有__init__.py文件(除非它在sys.path中某个文件夹下)。

    错误的import做法

    如上述project中,如果你想让subpackage2中的foo2来import subpackage1中的foo1,便会出现找不到subpackage1的情况。

    目前网络上大部分的做法都是通过sys.path.append(yourpath)之类的方法,将你需要import的module的目录添加到sys.path中。或者,通过修改PYTHONPATH这个环境变量来将添加(跟修改sys.path效果相同)。

    但是,这种做法有如下几个缺点:

    • 如果你用PYTHONPATH,那么当有多个项目时,你需要把每个项目的根目录都加入到PYTHONPATH中,会使得PYTHONPATH变得十分臃肿
    • 如果你使用sys.path,由于文件夹是动态添加的,所以当你使用相对路径的时候,实际路径会十分依赖于你的入口函数,当入口函数改变很可能就会导致代码无法运行
    • 如果你使用绝对路径,将你的代码在其他机器上运行的时候需要重新配置这些变量,十分麻烦

    正确的做法

    代码中正常import

    首先,在代码中按照正常方式导入你需要的包

    比如,你需要在app.py中导入foo1,则:

    from package.subpackage1 import foo1 
    • 1

    虽然你可能发现from subpackage1 import foo1也可以正常运行,但是请避免这种使用相对路径的方法。因为这在python3中将不再支持,同时也有可能会引起奇怪的问题。同时,虽然PEP 328中也给出了 from .subpackage1 import foo1这样的形式,但是还是不要自己给自己制造麻烦,统一使用完整路径(绝对路径)为好。

    再比如,如果你需要在foo2.py中导入foo1.py(在不同的subpackage中),则:

    from package.subpackage1 import foo1
    • 1

    跟上面一模一样,这就是使用绝对路径的好处,各处的引用高度统一。同时,如果你的package被安装在其他用户的机器中,其他用户也会使用这种绝对路径来import你package中的模块(回想你自己import第三方package的情景)。

    创建__main__.py文件

    在package的根目录中创建__main__.py文件,可以使得你的package可以通过python -m直接运行。

    demo中的__main__.py文件十分简单:

    from package.app import main
    main()
    • 1
    • 2

    即import真正的主函数app.py中的main方法,然后调用main()

    用python -m运行你的python文件

    python的-m参数官方说法是: 
    Searches sys.path for the named module and runs the corresponding .py file as a script.

    在下面的例子中,加上-m参数后,所运行的.py文件便会识别其顶层的package

    回到刚才的例子。创建完__main__.py之后,cd到项目的根目录,运行

    python -m package
    • 1

    即可实现直接运行__main__.py,即直接运行了package这个包

    如果你想直接运行package内的某个.py文件,比如foo1,则:

    python -m package.subpackage1.foo1
    • 1

    当然,你要确保foo1中存在判断其是否是入口函数的逻辑,如下:

    if __name__ == "__main__":
        speak()
    • 1
    • 2

    总结

    至此,我们已经实现了你所希望的所有功能:

    • 在project内部实现各个模块之间的import
    • project中的各个.py文件可以直接运行
    • 将project迁移到其他机器时,不用进行额外配置

    如果还有不明白的,可以将github上的源码下载下来看一看,然后用python -m运行一下

  • 相关阅读:
    bootstrap-table对前台页面表格的支持
    解决拦截器对ajax请求的的拦截
    jQuery获取鼠标事件源(万能)
    HtmlAgilityPack 处理通配的contains
    【转】XPath的学习
    在IIS服务器上部署svg/woff/woff2字体
    【转】万网域名查询接口(API)的说明
    html5和css3的常用参考网
    【转】Xml序列化
    C#序列化s实体类成Xml,去除空格、换行符以及命名空间
  • 原文地址:https://www.cnblogs.com/he12345/p/7510767.html
Copyright © 2011-2022 走看看