day24 包

1.   包

  包是一种通过 '.模块名'来组python模块名称间的形. 那什么样的东西是包呢?
建的个文件夹都可以被称之为包. 但是我们要注意, python2. 包内必须存
__init__.py文. 建包的目的不是为了运行, 而是被入使用. 包只是一种式而已. 包的本
就是一种模块

  为何要使用包? 包的本就是一个文件夹, 那么文件夹唯一的功能就是起来,
功能, 我们无所有功能都在一个文, 于是我们使用模块去组功能,
模块, 我们就要一个件夹将模块文起来, 以此来提高程序的结性和可
维护

首先, 我们先建一些包. 用来作为接下来的. 包很好. 只要是一个文件夹,
init__.py就可以 (尽管python3不要求,为了安全起见还是装了比较保险)

import os
os.makedirs('glance/api')
os.makedirs('glance/cmd')
os.makedirs('glance/db')
l = []
l.append(open('glance/__init__.py','w'))
l.append(open('glance/api/__init__.py','w'))
l.append(open('glance/api/policy.py','w'))
l.append(open('glance/api/versions.py','w'))
l.append(open('glance/cmd/__init__.py','w'))
l.append(open('glance/cmd/manage.py','w'))
l.append(open('glance/db/__init__.py','w'))
l.append(open('glance/db/models.py','w'))
map(lambda f:f.close() ,l)

运行上面的代码就会创建一个这样的目录

接着把文件目录对应的文件写进去这些东西

#policy.py
def get():
print('from policy.py')
#versions.py
def create_resource(conf):
print('from version.py: ',conf)
#manage.py
def main():
print('from manage.py')
#models.py
def register_models(engine):
print('from models.py: ',engine)

接下来. 我们在test中使用包中的内容. 并且, 我们入包的时候可以使用import或者
from xxx import xxx这种.
首先, 我们看import

import glance.db.models
glance.db.models.register_models('mysql')
#没问题,可以正常运行

 我们还可以使⽤from xxx import xxx 入包内的模块

from glance.api.policy import get
get()

也没问题,但是着白要注意的是from xxx import xxx这种, import后⾯不可以出现""
就是说from a.b import cok. 但是 from a import b.c 是错误的

 

2.   __init__

包里的__init__.py是什么鬼? 其实.
我们使用种方入一个包, 只要是第一次入包或者是包的何其他部分, 都会先执行
__init__.py文. 这个文可以是. 但也可以存放⼀些初始化的代码. (随意在glance中的
__init__.py都可以进行测试)

 

那我们之前用的from xxx import *还可以⽤么? 可以. 我们要在__init__.py文
__all__* 入的内容.

#在__init__文件中
print
("我是glance的__init__.py⽂件. ") x = 10 def hehe(): print("我是呵呵") def haha(): print("我是哈哈") __all__ = ['x', "hehe"]

在test文件中

from glance import *
print(x) # OK
hehe() # OK
haha() # 报错. __all__没有这个东西

 

3   .绝对导入和相对导入

我们的最顶级包glance是写给别人用.
后再glance包内部也会有此之间入的需求, 这时候就有入和相对入两种
方式了.
1. : glance作为起

2. 相对: 以. 或者..作为起始(.当前文件躲在目录, ..当前文件所在目录的上一级目录)
例如, 我们在glance/api/version.py中使用glance/cmd/manage.py

# 在glance/api/version.py
#绝对导入
from glance.cmd import manage
manage.main()

 

 

#相对导入
# 这种情形不可以在versions中启动程序.
# attempted relative import beyond top-level package
from ..cmd import manage
manage.main()

 

测试的时候要注意. python路径跟运行本所在的目有关系. 说白了. 就是你运行
py文所在的目. python中不允许你运行的程序包的时候过当前包的范围(相对
). 如果使用. 没有这个问题. 个说法. 如果你在包内使用了相对. 那在使用
包内信息的时候. 只能在包外面.

 

接下来. 我们来看一个大坑. 比如. 我们想在policy中使用verson中的内容.

# 在policy.py
import versions

如果我们程序的入口policy.py 那此时程序是没有何问题的. 但是如果我们在glance
外面importglance中的policy就会原因是如果在外面访policy的时候. sys.path中的
路径就是外面. 所以本就不能直接找到versions模块. 所以一定会:

ModuleNotFoundError: No module named 'versions

包出错的时候. 一定要先看sys.path 看一下是否真的能获取到包的信息.

, 我们看一下如何单独导入一个包

# 在test.py中  test.py和glance是同级的
import glance

此时入的glance什么都不了. 为在glance中的__init__.py中并没有关于⼦包的加
. 此时我们要在__init__.py中分入⼦包中的内容.
1. 使用路径
2. 使用相对路径

 

包的注意事项:
1. 关于包相关的语句也分为importfrom xxx import xxx两种, 但无使用,
无论在什么位, 入时都必须遵循三: 是在入时d点的. 左边必须是一
个包. . 可以带一串的点. 比如a.b.c,对于导入后,在使用时就没有这种限制了,

点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。

2. import入文. 产生名称间中的名字来于文, import , 产生的名称
中的名字同样来于文, 包下的__init__,py, 入包本就是在该文
3. A和包B下有同名模块也不会冲突, A.aB.a来自两个名称

模块的搜索路径

python解释器在启动时会自动加载一些模块,可以使用sys.modules查看
 
在第一次导入某个模块时(比如my_module),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用
 
如果没有,解释器则会查找同名的内建模块,如果还没有找到就从sys.path给出的目录列表中依次寻找my_module.py文件。
 
所以总结模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
 
sys.path的初始化的值来自于:
 
The directory containing the input script (or the current directory when no file is specified).
PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
The installation-dependent default.
 
需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。虽然每次都说,但是仍然会有人不停的犯错。 
 
在初始化后,python程序可以修改sys.path,路径放到前面的优先于标准库被加载。
import sys
sys.path.append('/a/b/c/d')
sys.path.insert(0,'/x/y/z') #排在前的目录,优先被搜索

注意:搜索时按照sys.path中从左到右的顺序查找,位于前的优先被查找,sys.path中还可能包含.zip归档文件和.egg文件,python会把.zip归档文件当成一个目录去处理。

 

#首先制作归档文件:zip module.zip foo.py bar.py

import sys
sys.path.append('module.zip')
import foo,bar

#也可以使用zip中目录结构的具体位置
sys.path.append('module.zip/lib/python')

#windows下的路径不加r开头,会语法错误
sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\a')

 

包是一种通过使用‘.模块名’来组织python模块名称空间的方式。
 
1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法
 
2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)
 
3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
 
强调:
 
  1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
 
  2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块

 

 

 

 

 

如果当前有重名read1或者read2,那么会有覆盖效果。

 

#插一个点
#my_module.py
print('from the my_module.py')

money=1000

def read1():
    print('my_module->read1->money',money)

def read2():
    print('my_module->read2 calling read1')
    read1()

def change():
    global money
    money=0

my_module模块

 

#测试三:导入的函数read1,被当前位置定义的read1覆盖掉了
#demo.py
from my_module import read1
def read1():
    print('==========')
read1()
'''
执行结果:
from the my_module.py
==========
'''

 

 注:

,每个模块只被导入一次,放入字典sys.modules中,如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块,

有的同学可能会想到直接从sys.modules中删除一个模块不就可以卸载了吗,注意了,你删了sys.modules中的模块对象仍然可能被其他程序的组件所引用,因而不会被清除。

特别的对于我们引用了这个模块中的一个类,用这个类产生了很多对象,因而这些对象都有关于这个模块的引用。

 

 

posted @ 2018-11-20 14:18  阿布_alone  阅读(171)  评论(0编辑  收藏  举报
TOP