python import详解 创建自己的包 跨文件夹引用包

基础语法

在python用import或者from…import来导入相应的模块。模块其实就一些函数和类的集合文件,它能实现一些相应的功能,当我们需要使用这些功能的时候,直接把相应的模块导入到我们的程序中,我们就可以使用了。这类似于C语言中的include头文件,Python中我们用import导入我们需要的模块。

import语句可以出现在程序中的任何位置。但是有一点是:无论import语句被使用了多少次,每个模块中的代码仅加载和执行一次,后续的import语句仅将模块名称绑定到前一次导入所创建的模块对象上。

一般说来,应该避免使用from…import而使用import语句

因为这样可以使你的程序更加易读,也可以避免名称的冲突

from folder1.folder2.filename import *
import filename
import filename as modulename
from folder1.folder2.filename import * 


import somemodule
import somemodule as module1
from somemodule import *
from somemodule import somefunction
from somemodule import somefunction1,somefunction2
from somemodule import somefunction as fun1
# somemodule 为py文件的前缀名字
# somemodule 为folder1.folder2.filename(folder1文件夹下folder2的文件filename)

在使用 from xxx import * 时,如果想精准的控制模块导入的内容,可以使用 __all__= [xxx,xxx] 来实现,例如:

import sys
import os

search_path = '/home/zhouziqun/'
if search_path not in sys.path:
    sys.path.append(search_path)

from project.test_import.test1 import * 

print(a)
print(b)
print(c)

test1内容

__all__ = ['a','b'] #__为双横线
a = 100
b = 200
c = 300

如果把 test1.py中 __all__给注释掉,那么上面的代码执行起来就不会有问题, import *默认的行为是从给定的命名空间导出所有的符号(当然下划线开头的私有变量除外)。

需要注意的是 __all__只影响到了 from import *这种导入方式,对于 from import 导入方式并没有影响,仍然可以从外部导入。

创建自己的模块

在创建之前,有一点需要说明一下:每个Python模块都有它的__name__(就每个对象都自己的__doc__一样)。通过__name__我们可以找出每一个模块的名称,一般__name__的值有种:

1 一是主模块名称为:"__main__"(可以理解为直接运行的那个文件),

2 那些被主模块导入的模块名称为:文件名字(不加后面的.py)。

有__name__是很有用的,因为我们可以通过 if __name__ == ‘xxx’ 判断来执行那些模块,那些模块不被执行。另外:每个Python程序也是一个模块。它扩展名为:.py扩展名。

下面,我们通过例子来说明:
首先:我们创建模块:mymodel.py

#Filename:mymodel.py
version = '1.0'
def sayHello():
    print ('Hello world')

def modelName():
    return __name__#返回它自己的名称
#end of model

以上语句注意:

1 这个模块应该被放置在我们输入它的程序的同一个目录中,或者在sys.path所列目录之一。放置在我们输入它的程序的同一个目录中时候不需要特意添加搜索包的路径。如果在其他地方请参考后文的跨文件引用的几种方法

2 你已经看到,它与我们普通的Python程序相比并没有什么特别之处。然后:我们在test.py中来调用此模块:mymodel.py

import sys
sys.path.append('the path of mymodule')#提供搜索路径
import mymodule
print(__name__) #此处打印主模块的名称:__main__  因为在主模块中运行
mymodel.sayHello()
print('Version',mymodel.version)
print('Model Name',mymodel.modelName())#打印被导入模块的名称: mymodel

# 我们使用from..import...
print('======================from.....import=====================================')
from mymodel import *
print(__name__)#此处打印主模块的名称:__main__
sayHello()
print('Version',version)
print('Model Name',modelName()) 
#打印被导入模块的名称: mymodel

创建自己的包

1 一个包的基本组织如下:

#  /home/zhouziqun/project/test1/
#   __init__.py
#   lib/
#     __init__.py
#     one.py
#        a = 100
#     two.py
#        b = 200
#     ....
#   model/
#     __init__.py
#     main.py
#     ....


在外部加载调用时,有以下方式:
import sys
sys.path.append('/home/zhouziqun/project/')#提供搜索路径
#加载方式一
import test1.lib.one
print (test1.lib.one)
#加载方式二
from test1.lib import one
print (one.a)
#加载方式三
from test1.lib.one import a
print (a)
#加载方式四
from test1.lib import *
print (one.a)
print (two.b)
注意直接使用第四种方式是不能正确导入test1.lib下的one子模块的,这就需要在目录下的__init__.py文件中定义好需要加载子模块的名称
test1/lib/__init__.py
__all__=['one','two'] #定义加载子模块的名称

在加载包模块时,在import语句执行期时,遇到的所有__init__.py文件都会被执行,在上面代码中
首先会执行Fc目录中的__int__.py,然后执行lib目录中的__init__.py

2 子模块加子模块问题

主程序的时候不可以使用相对地址

首先因为主程序使用加载文件时,会为其指定一个名称(存储在其__name__属性中)。如果它作为顶级脚本加载,则其名称为__main__。如果它作为模块加载,则其名称是文件名,前面是作为其一部分的任何包/子包的名称,以点分隔。所以当你在以主程序运行的时候进行模块添加用点分隔或者相对路径引入的时候是通过__main__进行查找的,就很有可能找不到,得根据添加的搜索路径进行所有模块的绝对路径引入。

子模块之间的相互引用可以使用相对地址

因为还是在子模块被import入主文件的时候,文件名和路径名是不变的,所以还可以继续在子文件中进行import引入

下面看例子

#  /home/zhouziqun/project/test1/
#   __init__.py
#   lib/
#     __init__.py
#     one.py
#        a = 100
#     importtest.py 文件内容见下
#   two.py
#      b = 200
#     ....
#     ....
#   model/
#     __init__.py
#     main.py
#     three.py
#     four.py
#     ....

#importtest.py文件内容
# 同一包的相同同目录中:使用相对导入
from . import one
# 同一包的不同目录中:使用相对导入
from .. import two
from ..model import four
# 使用完全限定名称
#这个时候不需要再添加路径了  因为总文件已经添加过啦
from test1.model import three
# #加载方式:(这种方式应当避免:最后找不到会转移到标准库)
# import test1.lib.one
# # 需要设置好init文件
# from . import *
# print(one.a)


#main.py文件内容
import sys
sys.path.append('/home/zhouziqun/project/')#提供搜索路径

from test1.lib import importtest

print(importtest.one.a)
print(importtest.two.b)
print(importtest.three.c)
print(importtest.four.abcd)
print(importtest.four.dcba)
print(sys.modules)

另外在导入一个包时,会定义一个特殊的变量__path__,该变量包含一个目录列表。
__path__可通过__init__.py文件中包含的代码访问,最初包含的一项具有包的目录名称。我们可以向__path__列表提供更多的目录,以更改查找子模块时使用的搜索路径,大型项目中这个很有用。

使用sys.modules可查看当前加载的所有模块。

跨文件夹引用或者跨环境引用包

Python以目录来组织模块, 就是所谓的包. 用包的一大好处: 可以解决名字空间冲突的问题, 即文件重名问题.

函数添加即时生效

这是即时生效的方法,就是在模块里面修改sys.path值,这种方法修改的sys.path作用域只是当前进程,进程结束后就失效了。 比较干净, 避免一些冲突问题。

最好加个判断,避免重复加入

语法例子:

主运行文件

import sys
import os

print("添加路径前所有查找路径")
print("\n".join(sys.path))


search_path = '/home/zhouziqun/'
if search_path not in sys.path:
	sys.path.append(search_path)
import testzzq

print("添加路径后所有查找路径")
print("\n".join(sys.path))

print(testzzq.a)
print(testzzq.addzzq(1,2))

/home/zhouziqun/testzzq.py文件内容

a = 9
def addzzq(a,b):
    return a+b

由此可以安装一些不同路径下的软件包

运行结果:

添加路径文件长期有效

在site-packages/ 增加一个路径文件,必须以.pth为后缀,将模块的路径写进去,一行一个路径,写上要加入的模块文件所在的目录名称。这种方法一劳永逸, 简单暴力。

在之前搜索到的路径site-packages/下新建一个pth文件里面内容如下:

/home/zhouziqun/

运行原始文件修改程序

import sys
import os

print("添加路径前所有查找路径")
print("\n".join(sys.path))

import testzzq


print(testzzq.a)
print(testzzq.addzzq(1,2))

结果

发现在添加路径之前就已经有固定的路径显示也就是说默认搜索路径中有了这个路径

修改环境变量

添加系统环境变量PYTHONPATH,在这个环境变量中输入相关的路径,不同的路径之间用逗号(英文的!)分开。路径会自动加入到sys.path中。

Python搜索模块的路径:
1)、程序的主目录
2)、PTYHONPATH目录(如果已经进行了设置)
3)、标准连接库目录(一般在/usr/local/lib/python2.X/)
4)、任何的.pth文件的内容(如果存在的话).新功能,允许用户把有效果的目录添加到模块搜索路径中去
.pth后缀的文本文件中一行一行的地列出目录。
这四个组建组合起来就变成了sys.path了,

import sys
sys.path
导入时,Python会自动由左到右搜索这个列表中每个目录。

执行命令: touch ~/.bash_profile

PATH="/Library/Python/2.7/site-packages:${PATH}"
export PATH
PYTHONPATH="/Library/Python/2.7/site-packages:{$PYTHONPATH}"
export PYTHONPATH

保存后的环境变量不会立即生效,需要执行 source ~/.bash_profile

猜你喜欢

转载自blog.csdn.net/qq_41554005/article/details/90138488