python文件间模块调用

        一般项目中模块一般会分布在文件系统的不同路径中。Python解释器找到某个模块并将其导入命名空间会遵循一定的搜索规则,这个规则就是模块路径搜索顺序。

模块路径搜索

python搜索模块的路径顺序:

1)、程序运行的工作目录

2)、PTYHONPATH目录(如果已经进行了设置)

3)、标准连接库目录(linux下一般在/usr/local/lib/python2.X/)

4)、任何的.pth文件的内容(如果存在的话).新功能,允许用户把有效果的目录添加到模块搜索路径中去,.pth后缀的文本文件中一行一行的地列出目录。

这四个组合起来就变成了sys.path了。sys.path是python的搜索模块的路径集,是一个list,如

>>> importsys

>>>sys.path

['','/usr/lib64/python27.zip', '/usr/lib64/python2.7','/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk','/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload','/root/.local/lib/python2.7/site-packages', '/usr/lib64/python2.7/site-packages','/usr/lib64/python2.7/site-packages/gtk-2.0','/usr/lib/python2.7/site-packages']

>>> 

          因此只要模块或者包所在的目录在sys.path中,就可以使用import 模块或import 包命令格式来使用。下面以如下一个文件结构为例

[root@localhostpython]# tree

.

├──moduleA.py

├──mylib

   ├──moduleB_2.py

   ├──moduleB.py

   └──sublib

    ├──moduleC.py

├──otherlib

   ├──moduleD.py

└──run.py

同级目录导入

         处于同级目录的两个模块直接使用import 或from 模块名 import *相互调用。但这也只限于其中一个模块文件作为主程序运行。如在run.py中下列导入是合法的导入

import moduleA

     而无法直接导入其他目录中的模块,如import moduleB是非法的。而且指定全路径也是极其错误的,如import /test/python/mylib/moduleB,这和php不一样。

        而且导入过程和python解释器当前工作目录无关,

[root@localhostpython]# python run.py

in moduleA file

in run file

[root@localhostpython]# cd ..

[root@localhosttest]# python python/run.py

in moduleA file

in run file


跨目录调用

    跨目录调用分以下几种情况

[if !supportLists]•     [endif]主程序所在的目录是模块所在目录的父(或祖辈)目录

[if !supportLists]•     [endif]主程序导入上层目录中的模块

跨目录导入有统一的导入模式,可以使用sys.path.append方法将模块加入到程序搜索路径中。如在run.py中导入moduleB.py,我们可以这么做

[root@localhostpython]# vi run.py

import sys

sys.path.append('/test/python/mylib')

 

import moduleB

print("in runfile")

再次运行

[root@localhostpython]# python run.py

in moduleB file

in run file

      使用这种方法有两个缺点,一是在退出python环境后自己添加的路径就会自动消失了,且它是在实践中极为脆弱,应尽量避免使用;二是它将目录名硬编码到了你的源代码。如果你的代码被移到一个新的位置,这会导致维护问题。

      为了解决这些问题,可以有以下两个方法。

       使用PYTHONPATH环境变量来添加。在自定义应用程序中,这样的环境变量可在程序启动时设置或通过shell 脚本。如shell中,

[root@localhost python]# export PYTHONPATH=/usr/lib/

[root@localhost python]# python

Python 2.7.5 (default, Apr  92019, 14:30:50)

[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux2

Type "help", "copyright", "credits" or"license" for more information.

>>> import sys

>>> sys.path

['', '/usr/lib','/usr/lib64/python27.zip', '/usr/lib64/python2.7','/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk','/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload','/root/.local/lib/python2.7/site-packages','/usr/lib64/python2.7/site-packages','/usr/lib64/python2.7/site-packages/gtk-2.0','/usr/lib/python2.7/site-packages']

>>> 

        上述操作只针对当前窗口生效,我们可以vi /etc/profile,在最后添加 export PYTHONPATH=/usr/lib/对所有用户生效。

         使用.pth文件,在site-packages 文件中创建 .pth文件,将模块的路径写进去,一行一个路径。site-packages目录是第三方包和模块安装的目录。如果你手动安装你的代码,它将被安装到site-packages目录。虽然用于配置path的.pth 文件必须放置在site-packages里,但它配置的路径可以是系统上任何你希望的目录。因此,你可以把你的代码放在一系列不同的目录,只要那些目录包含在.pth 文件里。

         除了上述方法外,还可以将模块封装成包,见下节。

python中,每个py文件被称之为模块,而每个包含有__init__.py文件的目录或文件夹被称为包。在创建许许多多模块后,我们可能希望将某些功能相近的文件组织在同一文件夹下,在这个文件夹下再增加一个 __init__.py文件,这个文件夹就成为了包。即包是python模块文件所在的目录,且该目录下必须存在__init__.py文件。典型的包结构如下:

package

├── __init__.py

├── module_a.py

└── module_b.py

          最简单的情况下,只需要一个空的 __init__.py 文件即可。当然它也可以执行包的初始化代码或者设置__all__值。包下面是一些模块文件和子目录,假如子目录中也有 __init__.py 那么它就是这个包的子包了。

        包的使用同模块一样,使用 import 、 from ... import 语句,来改变命名空间。

__init__.py

  如上所述,封装成包是很简单的。在文件系统上组织你的代码,并确保每个目录都定义了一个__init__.py文件。

如在mylib文件夹下新建一个__init__文件。

[root@localhost mylib]# touch __init__.py

那么mylib目录现在就是一个包。如果要在run.py中导入moduleB.py模块,可以写入如下格式导入moduleB.py

[root@localhost python]# vi run.py

import mylib.moduleB

….

[root@localhost python]# python run.py

in moduleB file

in run file

即导入包中的模块使用如下格式

pkg1.pkg2.~.pkgn.模块名

包的导入注意点凡是在导入时带点的,点的左边都必须是一个包,否则非法。如果想要导入moduleC.py模块,还需要在sublib目录下新建__init__.py文件。如

[root@localhost sublib]# touch __init__.py

[root@localhost python]#vi run.py

import mylib.sublib.moduleC

[root@localhost python]# python run.py

in moduleC file

in run file

 

       上述导入指明了包的全路径,这个路径(顶层包名)是相对于主程序所在目录而言的,

[root@localhost mylib]# vi moduleB.py

import otherlib.moduleD             #导入otherlib

import moduleB_2                  #同目录下的模块

print("in moduleB file")

 

[root@localhost mylib]# python moduleB.py

Traceback (most recent call last):

  File "moduleB.py",line 1, in

    import otherlib.moduleD

ImportError: No module named otherlib.moduleD

这是因为moduleB.py所在的mylib目录下没有otherlib包。

这也意味着我们在导入模块的时候,最好写全包的路径(从顶层包开始),除非两个模块在同一个目录,如

[root@localhost python]# vi run.py

import mylib.moduleB                 #导入mylib

print("in run file")

 

[root@localhost python]# python run.py

in moduleD file

in moduleB_2 file

in moduleB file

in run file

 

       它的导入过程是解释器首先发现要导入mylib包下的moduleB.py,于是在该包下找到了moduleB.py,在导入该文件时,又发现需要导入otherlib包下的moduleD.py,于是去otherlib(就在当前主程序同目录下)包下找moduleD.py。

        以上的用法都是使用了包的全路径来导入的。这实际上算是一种绝对路径。使用绝对路径名的不利之处是这将顶层包名硬编码到你的源码中。如果你想重新组织它,你的代码将更脆,很难工作。举个例子,如果你改变了包名,你就必须检查所有文件来修正源码。同样,硬编码的名称会使移动代码变得困难。

   而相对路径中,用. 为当前目录,.. 为父目录。但这种方法只适用于from … import的导入方式。如

[root@localhost python]# vi run.py

import mylib.sublib.moduleC

print("in run file")

[root@localhost sublib]# cat moduleC.py

from .. import moduleB_2

#import mylib.moduleB_2

print("in moduleC file")

 

上述语句即实现在sublib/module.py中导入上层目录中的moduleB_2.py。

[root@localhost python]# python run.py

in moduleB_2 file

in moduleC file

in run file

注意Relative imports use a module’s name attribute to

determine that module’s position in the package hierarchy. Note that relative imports are based on the name of the current module.

       上述导入的过程是通过import mylib.sublib.moduleC找到moduleC.py文件,在该文件中,因为有相对导入语句,就以当前模块为参考,去找父目录下找moduleB_2.py,它实际上等价于import

mylib.moduleB_2。

top-levelscript

每一个被直接运行的python

script都会被视作是top-level script。top-level

script的__name__被自动设置成__main__。那么它所在的目录将不被python视为包,通过相对导入将不起作用,如

[root@localhost mylib]# vi moduleB.py

from . import moduleB_2

print("in moduleB file")

 

[root@localhost mylib]# python moduleB.py

Traceback (most recent call last):

  File "moduleB.py",line 3, in

    from . import moduleB_2

ValueError: Attempted relative import in non-package

       moduleB.py所在的目录现在不是包了,通过相对导入将不起作用。

再比如

[root@localhost mylib]# vi moduleB.py

import sublib.moduleC

print("in moduleB file")

 

[root@localhost mylib]# cat sublib/moduleC.py

from .. import moduleB_2

print("in moduleC file")

 

[root@localhost mylib]# python moduleB.py

Traceback (most recent call last):

  File "moduleB.py",line 1, in

    import sublib.moduleC

  File"/test/python/mylib/sublib/moduleC.py", line 1, in

    from .. import moduleB_2

ValueError: Attempted relative import beyond toplevel package

  这是因为moduleB.py作为主程序入口,mylib目录就不是包了,而sublib就变成了顶层包。在sublib/moduleC.py中使用相对导入使用父目录下的模块当然就不会被允许了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容