python成长之路【第十八篇】:python模块介绍、模块导入和重载
一、模块和命名空间
一般来说,Python程序往往由多个模块文件构成,通过import语句连接在一起。每个模块文件是一个独立完备的变量包,即一个命名空间。一个模块文件不能看到其他文件定义的变量名,除非它显示地导入了那个文件,所以模块文件在代码文件中起到了最小化命名冲突的作用。因为每个文件都是一个独立完备的命名空间,即使在他们拼写相同的情况下,一个文件的变量名是不会与另一个文件中的变量冲突的。
注意:import VS from:应该指出,from语句在某种意义上战胜了模块的名称空间分割的目的,因为from把变量从一个文件复制到另一个文件,这可能导致在导入的文件中相同名称的变量被覆盖(并且,如果发生这种情况的话,不会为你给出警告)。这根本上会导致名称空间重叠到一起,至少在复制的变量上会重叠。
二、模块介绍
模块:用来从逻辑上组织Python代码(变量,函数,类,逻辑:实现一个功能),本质就是.py结尾的Python文件(文件名:test.py,对应的模块名:test)
包:用来从逻辑上组织模块的,本质就是一个目录(必须带有一个__init__.py文件)
模块分类:
内置模块
自定义模块
第三方模块(需要安装才能使用)
注意:Python中的模块,在其他语言中叫做类库。
三、模块导入和重载
导入和重载提供了一种自然的程序启动的选择,因为导入操作将会在最后一步执行文件。
在典型的应用中,导入者得到了模块文件中在顶层所定义的所有变量名。这些变量名通常被赋值给通过模块函数、类、变量以及其他被导出的工具。这些往往都会在其他文件或程序中使用。表面上来看,一个模块文件的变量名可以通过两个Python语句读取--import和from,以及reload调用。
3.1、模块的显要特性:属性
从一般意义上来说,模块往往就是变量名的封装,被认作是命名空间。在一个包中的变量名就是所谓的属性:也就是说,属性就是绑定在特定的对象上的变量名。
举个例子,使用文本编辑器创建一个名为myfile.py的单行的Python模块文件,其内容如下:
- # cat myfile.py
- #!/usr/bin/env python3.5
- title = "The Meaning of Life"
当文件导入时,它的代码运行并生成了模块的属性。这个赋值语句创建了一个名为title的模块的属性。
可以通过两种不同的方法从其他组件获得这个模块的title属性:
第一种,可以通过使用import语句将模块作为一个整体载入,并使用模块名后跟一个属性名来获取它:
- >>> import myfile
- >>> print(myfile.title)
- The Meaning of Life
一般来说,这里的点号表达式代表了object.attribute的语法,可以从任何的object中取出其任意的属性,并且这是Python代码中的一个常用操作。在这里,我们已经使用了它去获取在模块myfile中的一个字符串变量title,即myfile.titile。
注意:一旦以import方法导入模块文件,内置的dir函数可以获得模块内部的可用的变量名的列表。
第二种,可以通过from语句从模块文件中获得(实际上是复制)变量名:(推荐)
- >>> from myfile import title
- >>> print(title)
- The Meaning of Life
from和import很相似,只不过增加了对载入组件的变量名的额外的赋值。从技术上讲,from复制了模块的属性,以便属性能够成为接收者的直接变量。因此,能够直接以title(一个变量)引用导入字符串而不是myfile.title(一个属性引用)。
无论使用的是import还是from去执行导入操作,模块文件myfile.py的语句都会执行,并且导入的组件(对应这里是交互式提示模式)在顶层文件中得到了变量名的读取权。也许在这个简单的例子中只有一个变量名(变量title被赋值给一个字符串),但是如果开始在模块中定义对象,例如,函数和类时,这个概念将会很有用。这样一些对象就变成了可重要的组件,可以通过变量名被一个或多个客户端模块读取。
在实际应用中,模块文件往往定义了一个以上的可被外部文件使用的变量名。
注意:import和from列出模块名时,都是使用myfile,没有.py后缀。这是因为Python在寻找实际文件时,依靠Python模块搜索的路径定位文件,找到后自动中加入后缀名。然而,系统shell命令行中,一定要记得加上后缀名,但是import语句中则不用。
3.2、导入模块的所有方法:
- import module_name #表示将模块中的所有代码加载到这个位置并赋值给变量module_name,并执行模块
- import libs.module_name #表示从libs目录下导入模块文件module_name,调用方法:libs.module_name.func()
- import module1_name,module2_name #同时导入多个模块
- from module_name import login,logout #相当于将module_name\login中的代码拿到当前位置执行
- from module_name import login as module_name_login #对导入模块中的方法取别名
- from libs.module_name import func #从目录下的模块文件中导入方法func,调用:func()
import本质:
导入模块的本质就是把Python文件解释一遍。
导入包的本质就是执行该包下的__init__.py文件。
导入优化:
from module_name import login
相比较import module_name,调用时module_name.test(),每次调用时都需要在os.path路径中检索导致效率降低,所以使用from...import...导入,这样相当于将方法直接拿到调用者中执行。
- #当调用者与被调用者处于同一级目录下时。也就是这里s1.py与auth.py在同一目录中。
- auth.py文件中的内容:
- def login():
- print("login...")
- s1.py文件中的内容:
- import auth #导入同级目录中的文件
- auth.login() #调用
- 执行s1.py,输出结果为:login…
- #当s1.py与libs目录同级时,s1.py调用libs/commons.py文件。
- commons.py文件中的内容:
- def md5_func():
- print("libs/commons.py")
- s1.py文件中的内容:
- import auth
- import libs.commons #导入方式为:目录名.文件名
- auth.login()
- libs.commons.md5_func() #调用方法为:目录名.文件名.方法
- 或者s1.py文件中的内容:
- from libs import commons #导入方式为:从libs目录中导入commons.py文件
- commons.md5_func() #调用方法为:文件.方法
- 执行s1.py,输出结果为:
- login...
- libs/commons.py
示例
3.3、import如何工作
导入其实是运行时的运算,程序第一次导入指定文件时,会执行三个步骤:
a、找到模块文件
b、编译成位码(需要时)
c、执行模块的代码来创建其所定义的对象
这三个步骤只在程序执行时,模块第一次导入时才会进行。在这之后,导入相同模块时,会跳过这三个步骤,而只提取内存中已加载的模块对象。python把载入的模块存储到一个名为sys.modules的表中(list(sys.modules.keys())),并在一次导入操作的开始检查该表。如果模块不存在,将会启动一个三个步骤的过程。
a、搜索
首先,Python必须查找到import语句所引用的模块文件。事实上,路径和后缀是刻意省略掉的,因为Python使用了标准模块搜索路径来找出import语句所对应的模块文件。
Python的模块查找路径:
- import sys
- for item in sys.path:
- print(item)
Python模块的查找顺序:
- 依次从上往下查找(上面的优先,且不再搜索后续路径),如果都没有找到,就报错。
- D:\oldboy\s14\day5 #执行脚本所在目录
- D:\oldboy\s14 #忽略这个目录,因为这个目录是因为pycharm自行添加的
- C:\Users\chen\AppData\Local\Programs\Python\Python35\python35.zip
- C:\Users\chen\AppData\Local\Programs\Python\Python35\DLLs
- C:\Users\chen\AppData\Local\Programs\Python\Python35\lib
- C:\Users\chen\AppData\Local\Programs\Python\Python35
- C:\Users\chen\AppData\Local\Programs\Python\Python35\lib\site-packages
注意:sys.path返回的结果是一个列表,当我们需要添加路径时,只需要向列表中追加即可。
修改Python的模块查找路径:
- 示例:__file__表示当前文件
- sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
模块文件选择:
- 文件名的后缀(例如,.py)是刻意从import语句中省略的。Python会选择在搜索路径中第一个符合导入文件名的文件。例如,import b形式的import叙述可能会加载。
- 源代码文件b.py
- 字节码文件b.pyc
- 目录b,包导入
- 编译扩展模块(通常用C或C++编写),导入时使用动态连接(例如,Linux的b.so以及windows的b.dll)
- 用C编写的编译好的内置模块,并通过静态连接至Python。
- ZIP文件组件,导入时会自动解压缩。
- 内存内映像,对于frozen可执行文件。
- java类,在jython版本的Python中。
- .NET组件,在IronPython版本的Python中。
b、编译(可选)
遍历模块搜索路径,找到符合import语句的源代码文件后,如果有必要的话,Python接下来会将其编译成字节码。
Python会检查文件的时间戳,如果发现字节码文件比源代码文件旧(例如,如果你修改过源文件),就会在程序运行时自动重新生成字节代码。否则,就会跳过源代码到字节码的编译步骤。
c、运行
import操作的最后步骤是执行模块的字节码。文件中所有语句会依次执行,从头到尾,而此步骤中任何对变量名的赋值运算,都会产生所得到的模块文件的属性。因此,这个执行步骤会生成模块代码所定义的所有工具。例如,文件中的def语句会在导入时执行,来创建函数,并将模块内的属性赋值给那些函数。之后,函数就能被程序中这个文件的导入者来调用。
3.4、重载
在默认情况下,只是在每次会话的第一次运行。在第一次导入之后,其他的导入都不会再工作,甚至在另一个窗口中改变并保存了模块的源代码文件也不行。
- $ cat script1.py
- #!/usr/bin/env python3
- print('hello world')
- $ python3
- >>> import script1 # 第一次导入操作完成后,会执行文件
- hello world
- >>> import script1 # 第二次导入不会执行
- >>>
因为导入时一个开销很大的操作,以至于每个文件、每个程序运行不能够重复多于一次。导入必须找到文件,将其编译成字节码,并且运行代码。
但是,如果真的想要Python在同一次会话中再次运行文件(不停止和重新启动会话),需要调用imp标准库模块中可用的reload函数。reload函数载入并运行了文件最新版本的代码,如果已经在另一个窗口中修改并保存了它,那将反应出修改变化。
- >>> from imp import reload
- >>> reload(script1)
- hello world
- <module 'script1' from '/home/chen/script1.py'>
python成长之路【第十八篇】:python模块介绍、模块导入和重载的更多相关文章
- python成长之路【第八篇】:异常处理
一.异常基础 在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!! 语法: try: pass except Exc ...
- Python之路(第十八篇)shutil 模块、zipfile模块、configparser模块
一.shutil 模块 1.shutil.copyfileobj(fsrc, fdst[, length]) 将文件内容拷贝到另一个文件中,需要打开文件 import shutil shutil.co ...
- Python成长之路【第四篇】模块儿
模块儿&包(* * * * *) 模块儿(modue)的概念 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多 ...
- Python之路(第十二篇)程序解耦、模块介绍\导入\安装、包
一.程序解耦 解耦总的一句话来说,减少依赖,抽象业务和逻辑,让各个功能实现独立. 直观理解“解耦”,就是我可以替换某个模块,对原来系统的功能不造成影响.是两个东西原来互相影响,现在让他们独立发展:核心 ...
- Python之路(第二十八篇) 面向对象进阶:类的装饰器、元类
一.类的装饰器 类作为一个对象,也可以被装饰. 例子 def wrap(obj): print("装饰器-----") obj.x = 1 obj.y = 3 obj.z = 5 ...
- python成长之路【第五篇】:python字符编码
在2.7环境中我们要写上这一行#-*- coding:utf-8 -*- 为什么我们要加这一行呢?这一样的意思是置顶编码类型为utf-8编码! 首先在看这个问题之前,咱们是否曾想过一个问题? 为什么我 ...
- python成长之路【第十三篇】:Python操作MySQL之pymysql
对于Python操作MySQL主要使用两种方式: 原生模块 pymsql ORM框架 SQLAchemy pymsql pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎 ...
- python成长之路【第七篇】:面向对象
概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向对象三大特性 面向 ...
- python成长之路【第四篇】:装饰器
实现装饰器的知识储备: 示例: def f1(): print("f1") 1.函数即“变量” #上面的示例中,函数f1为变量,它指向内存地址.而f1()表示函数执行. 2.高阶函 ...
- python成长之路【第三篇】:函数
1.函数基础 函数是python为了代码最大程度的重用和最小化代码冗余而提供的基本程序结构. 函数是一种设计工具,它能让程序员将复杂的系统分解为可管理的部件. 函数用于将相关功能打包并参数. pyth ...
随机推荐
- 使用Linux自定义自动补全命令完善自己的shell脚本
对于Linuxer来说,自动补全是再熟悉不过的一个功能了.当你在命令行敲下部分的命令时,肯定会本能地按下Tab键补全完整的命令,当然除了命令补全之外,还有文件名补全. Bash-completion ...
- spark 中的RDD编程 -以下基于Java api
1.RDD介绍: RDD,弹性分布式数据集,即分布式的元素集合.在spark中,对所有数据的操作不外乎是创建RDD.转化已有的RDD以及调用RDD操作进行求值.在这一切的背后,Spark会自动 ...
- 最通用的ibatis.Net使用sql server存储过程返回分页数据的详细例子
ibatis.Net是一个比较简单和灵活的ORM框架,今天我分享一个我的项目中使用sql server通用存储过程来分页的一个例子,用ibatis.Net框架统一返回分页数据为IList<Has ...
- Android组件生命周期(三)
Android系统试图尽可能长地保持一个应用程序进程,但是当内存低时它最终还是需要移除旧的进程.为了决定保持哪个进程及杀死哪个进程,Android将每个进程放入一个基于运行于其中的组件的重要性等级和这 ...
- --@angularJS--综合小实例1
<!DOCTYPE HTML><html ng-app="myapp"><head> <title>综合小实例</title& ...
- Struts2的一个入门实例----登录功能
一.搭建环境与测试 1.web.xml文件,配置核心Filter 1: <?xml version="1.0" encoding="UTF-8"?> ...
- HDU-4371-Alice and Bob
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4371 这题在比赛的时候看错了题意,卡了很久都没做出来,也没有再回头仔细去看题,所以没做出来,之后再看别 ...
- HDU1392(凸包)
Surround the Trees Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- 从php到浏览器的缓存机制,不得不看!
所有的php程序员都知道在php脚本里面执行 echo "1";访客的浏览器里面就会显示"1". 但是我们执行下面的代码的时候,并不是显示"1&quo ...
- Spark:控制日志输出级别
Spark:控制日志输出级别 终端修改 在pySpark终端可使用下面命令来改变日志级别 sc.setLogLevel("WARN") # 或者INFO等 修改日志设置文件 ** ...