当前位置: 首页 > news >正文

模块与包

模块

1.什么是模块

一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。

2.为什么要使用模块

 

    如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。

    随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用,

3.如何使用模块

1.创建名称空间,用来存放spam.py中定义的名字
2.基于刚刚创建的名称空间来执行spam.py模块
3.创建名字spam指向该名称空间,spam.名字的操作都是以spam.py为准
4.python3模块不支持重载,修改过它自己会重新运行,在python2中有reload
 

1.import

原始文件

#spam.py
print('from the spam.py')

money=1000

def read1():
    print('spam->read1->money',1000)

def read2():
    print('spam->read2 calling read')
    read1()

def change():
    global money
    money=0

 

模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,为了防止你重复导入,python的优化手段是:第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载大内存中的模块对象增加了一次引用,不会重新执行模块内的语句),如下 

#test.py
import spam #只在第一次导入时才执行spam.py内代码,此处的显式效果是只打印一次'from the spam.py',当然其他的顶级代码也都被执行了,只不过没有显示效果.
import spam
import spam
import spam

'''
执行结果:
from the spam.py
'''

 

我们可以从sys.module中找到当前已经加载的模块,sys.module是一个字典,内部包含模块名与模块对象的映射,该字典决定了导入模块时是否需要重新导入。

 

复制代码
 1 #测试一:money与spam.money不冲突
 2 #test.py
 3 import spam 
 4 money=10
 5 print(spam.money)
 6 
 7 '''
 8 执行结果:
 9 from the spam.py
10 1000
11 '''
复制代码
复制代码
 1 #测试二:read1与spam.read1不冲突
 2 #test.py
 3 import spam
 4 def read1():
 5     print('========')
 6 spam.read1()
 7 
 8 '''
 9 执行结果:
10 from the spam.py
11 spam->read1->money 1000
12 '''
复制代码
复制代码
 1 #测试三:执行spam.change()操作的全局变量money仍然是spam中的
 2 #test.py
 3 import spam
 4 money=1
 5 spam.change()
 6 print(money)
 7 
 8 '''
 9 执行结果:
10 from the spam.py
11 1
12 '''
复制代码

总结:首次导入模块spam时会做三件事:

1.为源文件(spam模块)创建新的名称空间,在spam中定义的函数和方法若是使用到了global时访问的就是这个名称空间。

2.在新创建的命名空间中执行模块中包含的代码,见初始导入import spam

3.创建名字spam来引用该命名空间

 

 

4. 为模块名起别名,相当于m1=1;m2=m1 

1 import spam as sm
2 print(sm.money)

 5. 为已经导入的模块起别名的方式对编写可扩展的代码很有用,假设有两个模块xmlreader.py和csvreader.py,它们都定义了函数read_data(filename):用来从文件中读取一些数据,但采用不同的输入格式。可以编写代码来选择性地挑选读取模块,例如

1 if file_format == 'xml':
2     import xmlreader as reader
3 elif file_format == 'csv':
4     import csvreader as reader
5 data=reader.read_date(filename)

 

6. 在一行导入多个模块

1 import sys,os,re

 

2.from...import

对比import spam,会将源文件的名称空间'spam'带到当前名称空间中,使用时必须是spam.名字的方式

而from 语句相当于import,也会创建新的名称空间,但是将spam中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了、

 1 from spam import read1,read2

 

这样在当前位置直接使用read1和read2就好了,执行时,仍然以spam.py文件全局名称空间

#测试一:导入的函数read1,执行时仍然回到spam.py中寻找全局变量money
#test.py
from spam import read1
money=1000
read1()
'''
执行结果:
from the spam.py
spam->read1->money 1000
'''

#测试二:导入的函数read2,执行时需要调用read1(),仍然回到spam.py中找read1()
#test.py
from spam import read2
def read1():
    print('==========')
read2()

'''
执行结果:
from the spam.py
spam->read2 calling read
spam->read1->money 1000
'''

 

(和import不一样) 如果当前有重名read1或者read2,那么会有覆盖效果。

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

 

 

需要特别强调的一点是:python中的变量赋值不是一种存储操作,而只是一种绑定关系,如下:

复制代码
 1 from spam import money,read1
 2 money=100 #将当前位置的名字money绑定到了100
 3 print(money) #打印当前的名字
 4 read1() #读取spam.py中的名字money,仍然为1000
 5 
 6 '''
 7 from the spam.py
 8 100
 9 spam->read1->money 1000
10 '''
复制代码

 

也支持as

1 from spam import read1 as read

 

也支持导入多行

1 from spam import (read1,
2                   read2,
3                   money)

 

from spam import * 把spam中所有的不是以下划线(_)开头的名字都导入到当前位置,大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。

 

 

from spam import * #将模块spam中所有的名字都导入到当前名称空间
print(money)
print(read1)
print(read2)
print(change)

'''
执行结果:
from the spam.py
1000
<function read1 at 0x1012e8158>
<function read2 at 0x1012e81e0>
<function change at 0x1012e8268>
'''

 

可以使用__all__来控制*(用来发布新版本) (只输出后面括号中规定的内容)

在spam.py中新增一行

__all__=['money','read1'] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字

 

#spam.py

__all__=['money','read1']

print('from the spam.py')

money=1000

def read1():
    print('spam->read1->money',1000)

def read2():
    print('spam->read2 calling read')
    read1()

def change():
    global money
    money=0

 

importlib.reload   相当于一个重载的功能

importlib.reload(modulename),这只能用于测试环境。

def func1():
    print('func1')

def func1():
    print('func1')
1 import time,importlib
2 import aa
3 
4 time.sleep(20)
5 # importlib.reload(aa)
6 aa.func1()

1 import time,importlib
2 import aa
3 
4 time.sleep(20)
5 # importlib.reload(aa)
6 aa.func1()

在20秒的等待时间里,修改aa.py中func1的内容,等待test.py的结果。

打开importlib注释,重新测试

 

把模块当成脚本来执行

 

我们可以通过模块的全局变量__name__来查看模块名:
当做脚本运行:
__name__ 等于'__main__'

当做模块导入:
__name__=

作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
if __name__ == '__main__':

 

模块搜索路径

 

python解释器在启动时会自动加载一些模块,可以使用sys.modules查看

在第一次导入某个模块时(比如spam),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用

如果没有,解释器则会查找同名的内建模块,如果还没有找到就从sys.path给出的目录列表中依次寻找spam.py文件。

所以总结模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块

 

os,sys可以被当成标准模块调用.

 

包是一种通过使用‘.模块名’来组织python模块名称空间的方式。

无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法

包的本质就是一个包含__init__.py文件的目录。
包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间

 

我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:

绝对导入:以glance作为起始

相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)

也是通过包的__init__.py文件来定义的.

 

注意事项
1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。

2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。

3.对比import item 和from item import name的应用场景:
如果我们想直接使用name那必须使用后者。

 

单独导入包

 

单独导入包名称时不会导入包中所有包含的所有子模块,如

复制代码
#在与glance同级的test.py中
import glance
glance.cmd.manage.main()

'''
执行结果:
AttributeError: module 'glance' has no attribute 'cmd'

''' 
复制代码

解决方法:

1 #glance/__init__.py
2 from . import cmd
3 
4 #glance/cmd/__init__.py
5 from . import manage

执行:

1 #在于glance同级的test.py中
2 import glance
3 glance.cmd.manage.main()

千万别问:__all__不能解决吗,__all__是用于控制from...import * ,fuck

 

编辑起始路径

1 import sys,os
2 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
3 print(sys.path)
4 from aaaa import glance

 针对要调用的glance文件做他的__init__ 文件定义。

from .api.policy import get
from .api.versions import create_resource
from .cmd.manage import main
from .db.models import register_models

调用glance下的函数

1 import glance
2 
3 print(glance.policy)
4 
5 glance.get()
6 glance.main()

 

转载于:https://www.cnblogs.com/jiangshitong/p/6797297.html

相关文章:

  • 生成模型和判别模型
  • 树莓派+pythonista实时监控系统
  • mysql开发之---使用游标双层嵌套对总表进行拆分为帖子表和回复表
  • window 下安装 wget 命令
  • V8 Ignition:JS 引擎与字节码的不解之缘
  • centos安装vsftp
  • 【zabbix系列】安装与加入host
  • 【Sets】使用Google Guava工程中Sets工具包,实现集合的并集/交集/补集/差集
  • JAVA多线程入门
  • 20145223 杨梦云 《网络对抗》 Web基础
  • ionic入门之数据绑定显示-1
  • TFS 测试用例导入、导出工具
  • IntelliJ IDEA搭建SpringBoot
  • Hadoop OutputFormat浅析
  • php7 安装yar 生成docker镜像
  • Effective Java 笔记(一)
  • GitUp, 你不可错过的秀外慧中的git工具
  • js对象的深浅拷贝
  • Nacos系列:Nacos的Java SDK使用
  • PhantomJS 安装
  • React-Native - 收藏集 - 掘金
  • scala基础语法(二)
  • Spark RDD学习: aggregate函数
  • springMvc学习笔记(2)
  • vue 配置sass、scss全局变量
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 巧用 TypeScript (一)
  • 移动端 h5开发相关内容总结(三)
  • 在Unity中实现一个简单的消息管理器
  • 正则学习笔记
  • 【云吞铺子】性能抖动剖析(二)
  • # Panda3d 碰撞检测系统介绍
  • #{}和${}的区别?
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (Python) SOAP Web Service (HTTP POST)
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (强烈推荐)移动端音视频从零到上手(上)
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)程序员技术练级攻略
  • .net 7 上传文件踩坑
  • .net core 依赖注入的基本用发
  • .Net MVC + EF搭建学生管理系统
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .NET处理HTTP请求
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • @ModelAttribute 注解
  • [ C++ ] STL---string类的使用指南
  • [ C++ ] 继承
  • [.net] 如何在mail的加入正文显示图片