一、导入模块的两种方式

方式一 import + 模块 导入

优点:该模块内的名字不会和当前名称空间的名字冲突

缺点:在使用这个模块下的功能或者名字的时候需要加前缀显得麻烦

方式二 from + 模块 import 名字(模块中的函数或者变量名或者*(全部导入))

优点:代码精简,使用模块中功能不需要加前缀

缺点:容易和当前名称空间的名字混淆

ps 两种导入都可以在后面as起个别名,看具体需求

两种方式的导入模块都发生了三件事

  1. 产生了一个模块的名称空间
  2. 运行模块.py代码,讲运行产生的名字都丢到模块的名称空间中

第三件事就是两者的区别,from是直接把这个名字放在了当前名称空间,但是这个名字指向的值还是在模块中

#方式一导入模块,两个名称空间的变量互不影响,需要模块前缀的原因
import text2 #text2中的x=1 x=20 print(text2.x)
#方式二导入模块
from text2 import x,f2#f2的功能是修改全局的x=2,返回一个x
print(x)
#此时在全局中有一个名字x他的内存地址和text2中的x共同指向text2模块中1的内存地址
>>>1
x=3 #x和1的绑定关系解除,和3建立绑定关系
print(x)
>>>3
res = f2() #调用函数f2 获取x,此时获取的是text2中的x=1,将x=2并返回
print(res)
>>>2
print(x)#访问的是当前名称空间的x
>>>3

二、模块搜索的路径的优先级

优先级:

  1. 内存(内置模块)
  2. 硬盘:按照sys.path中存放的文件顺序依次查找导入的模块
import sys
print(sys.path) ['C:\\Users\\HZ\\PycharmProjects\\python实训\\笔记', 'C:\\Users\\HZ\\PycharmProjects\\python实训', 'C:\\Program Files\\JetBrains\\PyCharm 2019.3.4\\plugins\\python\\helpers\\pycharm_display', 'C:\\Users\\HZ\\AppData\\Local\\Programs\\Python\\Python37\\python37.zip', 'C:\\Users\\HZ\\AppData\\Local\\Programs\\Python\\Python37\\DLLs', 'C:\\Users\\HZ\\AppData\\Local\\Programs\\Python\\Python37\\lib', 'C:\\Users\\HZ\\AppData\\Local\\Programs\\Python\\Python37', 'C:\\Users\\HZ\\PycharmProjects\\python实训\\venv', 'C:\\Users\\HZ\\PycharmProjects\\python实训\\venv\\lib\\site-packages', 'C:\\Users\\HZ\\PycharmProjects\\python实训\\venv\\lib\\site-packages\\setuptools-39.1.0-py3.7.egg', 'C:\\Users\\HZ\\PycharmProjects\\python实训\\venv\\lib\\site-packages\\pip-10.0.1-py3.7.egg', 'C:\\Program Files\\JetBrains\\PyCharm 2019.3.4\\plugins\\python\\helpers\\pycharm_matplotlib_backend']

通过实验验证加载顺序

import sys
import time
import text2#此时已经导入内存 text2.say() time.sleep(5)#我们把text2文件删除 import text2 text2.say()#发现还是能执行,说明加载顺序在内存中优先

可以通过sys.path路径的添加,导入其他文件内的模块

import sys

#sys.modules查看已经加载到内存的模块,不导入其他模块时加载的都是内置模块

sys.path.append(r"C:\Users\HZ\PycharmProjects\python实训\笔记\day9")

import day9

print(day9.x)

三、循环导入

上节课我们讲了函数的递归,循环导入的做法也类似,但是我们在写程序的时候千万不能出现循环导入,如果出现了这样的屎一样的代码,就用以下两种“屎上雕花”

# 方案一:导入语句放到最后,保证在导入时,所有名字都已经加载过
# 文件:m1.py
print('正在导入m1') x='m1' from m2 import y # 文件:m2.py
print('正在导入m2')
y='m2' from m1 import x # 文件:run.py内容如下,执行该文件,可以正常使用
import m1
print(m1.x)
print(m1.y) # 方案二:导入语句放到函数中,只有在调用函数时才会执行其内部代码
# 文件:m1.py
print('正在导入m1') def f1():
from m2 import y
print(x,y) x = 'm1' # 文件:m2.py
print('正在导入m2') def f2():
from m1 import x
print(x,y) y = 'm2' # 文件:run.py内容如下,执行该文件,可以正常使用
import m1 m1.f1()

四、区分py文件的两种用途

py文件有两种用途,一种是作为程序运行,一种是作为模块导入。

所以每个文件都有可能作为两种用途来使用,我们可以用代码区分

#foo.py
...
if __name__ == '__main__':
foo.py被当做脚本执行时运行的代码
else:
foo.py被当做模块导入时运行的代码

五、编写一个规范的模板

我们在编写程序的时候,要知道这个代码不仅是给自己看的也要给别人看的,所有要有可读性和易维护性,我们就要对代码中的一些功能加以解释,通常以一个统一的规范编写

"The module is used to..." #模块的文档描述

import sys #导入模块

x=1 #定义全局变量,如果非必须,则最好使用局部变量,这样可以提高代码的易维护性,并且可以节省内存提高性能

class Foo: #定义类,并写好类的注释
'Class Foo is used to...'
pass def test(): #定义函数,并写好函数的注释
'Function test is used to…'
pass if __name__ == '__main__': #主程序
test() #在被当做脚本执行时,执行此处的代码

五、包

1 什么是包

包就是一个包含有--init--.py文件的文件夹

2 为什么要有包

包的本质是模块的一种形式,包是用来被当做模块导入的

#1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

#2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模

3 包的相关使用

1、执行包下的__init__.py文件

2、产生一个新的名称空间用于存放__init__.py执行过程中产生的名字

3、在当前执行文件所在的名称空间中得到一个名字pool,该名字指向__init__.py的名称空间,例如pool.xxx和pool.yyy中的xxx和yyy都是来自于pool下的__init__.py,也就是说导入包时并不会导入包下所有的子模块与子包

导包的两种情景

3.1 在当前文件内导该文件内的包

#导入同级目录下包aaa内的f2模块
#导入包aaa的同时会执行__init__.py文件
from aaa import f2 f2.func2()

3.2 在当前文件内导该文件外的包

import sys,os
sys.path.append(os.path.dirname(os.path.dirname(__file__))) #导入上层目录下的aaa,我们需要把此时运行的文件的环境变量扩展到上层目录 不然无法找到aaa
from aaa import f1 f1.func1()

六、软件开发的目录规范

为了提高程序的可读性与可维护性,我们应该为软件设计良好的目录结构,这与规范的编码风格同等重要。软件的目录规范并无硬性标准,只要清晰可读即可,假设你的软件名为foo,笔者推荐目录结构如下

Foo/
|-- core/
| |-- core.py
|
|-- api/
| |-- api.py
|
|-- db/
| |-- db_handle.py
|
|-- lib/
| |-- common.py
|
|-- conf/
| |-- settings.py
|
|-- run.py
|-- setup.py
|-- requirements.txt
|-- README

简要解释一下:

• core/: 存放业务逻辑相关代码

• api/: 存放接口文件,接口主要用于为业务逻辑提供数据操作。

• db/: 存放操作数据库相关文件,主要用于与数据库交互

• lib/: 存放程序中常用的自定义模块

• conf/: 存放配置文件

• run.py: 程序的启动文件,一般放在项目的根目录下,因为在运行时会默认将运行文件所在的文件夹作为sys.path的第一个路径,这样就省去了处理环境变量的步骤

• setup.py: 安装、部署、打包的脚本。

• requirements.txt: 存放软件依赖的外部Python包列表。

• README: 项目说明文件。

除此之外,有一些方案给出了更加多的内容,比如LICENSE.txt,ChangeLog.txt文件等,主要是在项目需要开源时才会用到,请读者自行查阅。

关于README的内容,这个应该是每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。它需要说明以下几个事项:

1、软件定位,软件的基本功能;

2、运行代码的方法: 安装环境、启动命令等;

3、简要的使用说明;

4、代码目录结构说明,更详细点可以说明软件的基本原理;

5、常见问题说明。

一般来说,用setup.py来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情,这种方式普遍应用于开源项目中。不过这里的核心思想不是用标准化的工具来解决这些问题,而是说,一个项目一定要有一个安装部署工具,能快速便捷的在一台新机器上将环境装好、代码部署好和将程序运行起来。

requirements.txt文件的存在是为了方便开发者维护软件的依赖库。我们需要将开发过程中依赖库的信息添加进该文件中,避免在 setup.py安装依赖时漏掉软件包,同时也方便了使用者明确项目引用了哪些Python包。

这个文件的格式是每一行包含一个包依赖的说明,通常是flask>=0.10这种格式,要求是这个格式能被pip识别,这样就可以简单的通过 pip install -r requirements.txt来把所有Python依赖库都装好了,具体格式参照https://pip.readthedocs.io/en/1.1/requirements.html

最新文章

  1. Django的单元测试
  2. [ACM_搜索] Triangles(POJ1471,简单搜索,注意细节)
  3. 《ASP.NET1200例》统计网站访问量源代码
  4. [webkit移动开发笔记]之如何去除android上a标签产生的边框
  5. POJ3279 Catch That Cow(BFS)
  6. shell打印 倒等腰三角形
  7. [.net 面向对象程序设计深入](18)实战设计模式——设计模式使用场景及原则
  8. [Swift]LeetCode123. 买卖股票的最佳时机 III | Best Time to Buy and Sell Stock III
  9. springboot的@CrossOrigin注解解决细粒度的配置跨域
  10. Java代码优化小结(三)
  11. 转发:C#操作SQL Server数据库
  12. 再谈IE的浏览器模式和文档模式[转]
  13. 1552/3506. [CQOI2014]排序机械臂【平衡树-splay】
  14. 一个带bash,带glibc,中国时区,非root用户可运行crond命令的基于alpine镜像的Dockerfile
  15. vue项目运行报错:Module bulid failed: Error: Node Sass does not yet support your current environment
  16. javascript笔记(一)
  17. 用POST方法上传文件
  18. Weblogic多数据源(Multi Data Sources)应用实践
  19. tomcat 代码集
  20. 关于本科毕业设计期间对数据挖掘工具rapidminer的使用体验和心得,案例分享

热门文章

  1. Koa源码解析,带你实现一个迷你版的Koa
  2. Vue3 新特性
  3. jenkins初始化启动报错导致进入web页面如法安装插件
  4. go 项目目录结构
  5. Beta冲刺<1/10>
  6. vscode启动vue项目出错,给了管理员权限没用
  7. vwware虚拟机网卡的三种模式
  8. APP测试经验总结
  9. 关于idea的一些快捷键
  10. 入门大数据---Kafka的搭建与应用