目录
模块
概述
概述: 已经写好的一组功能的集合
问题: 目前而言代码比较少,代码都放在一个py文件中,还能维护,但是一个项目中,代码量往往比较大,
如果代码都放在一个py文件中,难以维护
解决: 为了解决该问题,可以将 具有相似功能的函数 代码 放到不同的py文件中去,方便维护,
同时也减少了每个py文件的代码
"""一个py文件就是一个模块"""
给py文件命名的时候,需要见名知意
优点:
1.提高了代码可维护性
2.提高了代码的复用性
3.可以导入很多功能模块 (标准库模块,自定义模块,第三方模块)
4.避免了变量名重复
模块导入的过程中发生了什么?
1.找到这个模块
2.判断这个模块是否被导入过了
3.如果没有被导入过
1.创建一个属于这个模块的命名空间
2.让模块的名字 指向 这个空间
3.执行这个模块中的代码
模块的类型:
内置模块 不需要我们自己安装的 解释器自带的
第三方模块 需要我们自己安装的模块
自定义模块 我们自己写的模块
创建模块和调用模块
create_module03.py 文件中
def printGood(): #定义了一些函数
print("wen is a very good man")
def printNice():
print("wen is a nice man")
def printHandsome():
print("wen is a handsome man")
name = "周杰伦" #定义了一些变量
print("哈哈")
------
call_module.py 文件中:
# 格式: import module[,module1] [,module2]
# import作用是导入一个功能模块,来使用, 可以导入多个模块
# module 代表的是模块名, 一个py文件就是一个模块 , 不需要加 .py后缀
# 模块名需要见名知意,遵循标识符命名规则
# 规范建议,模块应该一个一个的导入,导入顺序为:
# 1.内置模块
# 2.扩展(第三方)模块
# 3.自定义模块
import create_module03
#import create_module03
#import create_module03 可以多次导入,但是只会执行一次
# 原理:相当于执行了引入模块中代码,比如内含有print()会执行一次
# 怎么判断这个模块已经被导入过了???
import sys
print(sys.modules)
# 调用模块中的函数
# 格式: 模块名.函数名() 模块名.属性名
create_module03.printGood()
create_module03.printNice()
# 可以调用模块中的 变量
print(create_module03.name)
# 注意:如果模块中没有的,则不能调用
print(create_module03.age) # 错误代码,age未定义
# 如果自己的模块中,定义了与导入模块相同函数名的函数,自己定义的会覆盖导入的模块
def printNice():
print("min is a nice man")
调用模块的部分功能:
格式: from 模块名 import 函数/属性/ 类
# 作用: 从模块中导入 部分 功能模块来使用
from create_module03 import printNice # 注意这些函数后面没有括号,是被当做部分模块
#from create_module03 import printNice,name
#from create_module03 import printNice,printGood
from create_modeule03 import * # 这个表示把一个模块中的所有功能导入
# 所以下面即可使用所有功能,但是不提倡使用这种方式
------------------------------------------
from import导入的过程中发生了什么事儿?
1.找到要被导入的模块
2.判断这个模块是否被导入过
3.如果这个模块没被导入过(被导入过,跳过下面前两个步骤)
创建一个属于这个模块的命名空间
执行这个文件
找到你要导入的变量
给你要导入的变量创建一个引用,指向要导入的变量
my_module.py 文件中:
print(123)
name="min"
def read1():
print("这是1")
def read2():
print("这是2",name) # 单独调用read2()时,里面的name作为全局变量,会被引用
print(456)
------
from my_module import read1
def read1():
print('in my read1')
read1()
from my_module import read2
read2()
import * 和 __all__ # 其中__all__只能约束*导入的变量的内容
from my_module import *
print(name)
read1()
read2()
my_module.py 文件中:
__all__=["name","read1",] # 里面有的,才能被导入,只能是列表
# 给模块起别名,起了别名之后,使用这个模块就都使用别名引用变量了
# import my_module as m
# m.read1()
>>>示例
def func(dic, t='json'):
if t == 'json':
import json
return json.dumps(dic)
elif t == 'pickle':
import pickle
return pickle.dumps(dic)
# 用到别名
def func(dic, t='json'):
if t == 'json':
import json as aaa
elif t == 'pickle':
import pickle as aaa
return aaa.dumps(dic)
# 给导入的内容起别名
from my_module import read1 as r1,read2 as r2
def read1():
print('in my read1')
r1()
r2()
read1()
模块中引用的情况
模块间循环引用出现的问题:
上面在于,执行第一步时,相互跳转,导致未能全部读取一方的内容
模块之间不允许循环引用(无论多少个模块,形成环状就不行)
模块的加载与修改:
# 已经被导入的模块发生了修改,是不会被感知到的
# 要想修改的模块被正在运行中的程序感知到,重启这个程序
把模块当做脚本来用
# 执行一个py文件的方式:
# 在cmd执行,在python执行 : 直接执行这个文件 - 以脚本的形式运行这个文件
# 导入这个文件
# 都是py文件
# 直接运行这个文件 这个文件就是一个脚本
# 导入这个文件 这个文件就是一个模块
# if __name__ == '__main__':
# 代码
# 写在这里面的代码只有这个文件被当做脚本执行的时候才执行
# 当一个py文件
# 当做一个脚本的时候 : 能够独立的提供一个功能,能自主完成交互
# 当成一个模块的时候 : 能够被导入这调用这个功能,不能自主交互
# 一个文件中的__name__变量
# 当这个文件被当做脚本执行的时候 __name__ == '__main__'
# 当这个文件被当做模块导入的时候 __name__ == '模块的名字'
__name__属性的作用
问题: 当一个模块被其他模块导入的时候,会执行该模块中的代码,
而有些功能是不希望被导入的时候,执行的代码,可以使用 __name__ 属性来解决
__name__ :
1.是模块自动生成,自带的
2.如果自己执行 __name__ 的值是 __main__ ;
如果被其他模块导入时执行 __name__ 结果是自己的模块名
3.该值是自己根据调用的模式,自动赋值
# __name__的使用
def main():
pass
if __name__ == "__main__":
# main函数
main()
# 写代码时,只要写出 main,回车会自动生成
if __name__ == "__main__": # 这句话表示的就是自己执行,被其他模块调用时不执行
模块的搜索路径
# 模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
# lib里面放的是内置模块
# 扩展模块一般在site-packages中
# sys.path:
# 注意:搜索时按照sys.path中从左到右的顺序查找,位于前的优先被查找,sys.path中还可能包含.zip归档文件和.egg文件,python会把.zip归档文件当成一个目录去处理。
# 千万不要自己定义这些你熟悉的模块或关键字啊啥的作为自己的模块名
# 被当做脚本执行的文件 同目录下的模块,可以被直接导入
# 除此之外其他路径下的模块 在被导入的时候需要自己修改sys.path列表
import sys
# import calculate
print(sys.path)
path = r'D:\sylar\s15\day21\5模块的循环引用'
sys.path.append(path)
编译python文件:
# 为了提高加载模块的速度,强调:提高的是加载速度而绝非运行速度。
# python解释器会在 __pycache__目录中下缓存每个模块编译后的版本,
# 格式为:module.version.pyc。通常会包含python的版本号。
# 1.以pyc为后缀的就为编译文件
# 2.编译pyc文件的时候,只有在导入文件的时候才做(就是作为一个模块的时候他才去编译)
包
概述
包是一种通过使用‘.模块名’来组织python模块名称空间的方式。
1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法
2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)
3. import导入文件时,产生名称空间中的名字来源于文件;import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
强调:
1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块
# 创建一个多层文件夹
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/models.py', 'w'))
# 目录结构
glance/ #Top-level package
├── __init__.py #Initialize the glance package
├── api #Subpackage for api
│ ├── __init__.py
│ ├── policy.py
│ └── versions.py
├── cmd #Subpackage for cmd
│ ├── __init__.py
│ └── manage.py
└── db #Subpackage for db
├── __init__.py
└── models.py
# 文件内容
# 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)
# 导入模块:
#import glance.api.policy as a
#glance.api.policy.get()
#a.get()
#from glance.api import policy
#policy.get()
from glance.api.policy import get
get()
1.关于包相关的导入语句也分为import和from ... import ...两种,
但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:
凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。
2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
3.对比import item 和from item import name的应用场景:
如果我们想直接使用name那必须使用后者。
from...import导入的模块,import后必须是明确的一个不能带点,否则会有语法错误,
如:from a import b.c是错误语法
导入包
直接导入包 ,需要通过设计init文件,来完成导入包之后的操作
导入一个包
不意味着这个包下面的所有内容都是可以被使用的
导入一个包到底发生什么了?
相当于执行了这个包下面的__init__.py文件
绝对导入:
在执行一个py脚本的时候,这个脚本以及和这个脚本同级的模块中只能用绝对导入
缺点:
所有的导入都要从一个根目录下往后解释文件夹之间的关系
如果当前导入包的文件和被导入的包的位置关系发生了变化,那么所有的init文件都要做相应的调整
# 想在 glance外层通过只导入包,来调用/glance/api/policy.y 中的get()
# 做法:
找到 glance下的__init__.py 配置:from glance import api
找到 api下的__init__.py 配置:from glance.api import policy
直到 import 前面是 目标包 后面是 方法的脚本为止
# 假如 和当前文件同级的是bbbb包,bbbb/glance;想同样来调用bbbb/glance/api/policy.y
# 做法:
不是直接调用bbbb同级包,而是跨级调用 glance包了,需要
from bbbb import glance
找到 bbbb 下的__init__.py 配置:from bbbb import glane
后面 即是上面 多添加一层 bbbb. 即可
相对导入:(必须放在包中的被导入时)
不需要去反复的修改路径
只要一个包中的所有文件夹和文件的相对位置不发生改变
也不需要去关心当前这个包和被执行的文件之间的层级关系
缺点:
含有相对导入的py文件不能被直接执行
必须放在包中被导入的调用才能正常的使用
import glance
glance.api.policy.get()
from bbbbb import glance2
glance2.api.policy.get()
from . import bbbbb # 含有相对导入的文件不能被直接执行
from bbbbb import demo1
如果只是从包中导入模块的话,那么我们不需要做任何多余的操作
直接导入就行了
import urllib # urllib是一个包,单纯的导入一个包啥也不会发生,包中的request.py也不能用
urllib.request
from urllib import request #从包中,导入一个模块
print(request)
如果我们希望导入包的时候,能够顺便把模块也导入进来
需要设计init文件
绝对目录的导入、相对目录的导入各有千秋
外层调用里层
#引入其他包中的模块
#格式: 包名.模块名
import test.testModule09
#调用内容
#格式: 包名.模块名.函数名()
test.testModule09.printGood()
里层调用外层
#如果内容和父级在同一层,可以直接调用
#如果大家都是在同一层、有父级就需要加上:包名.模块名 来调用;调用内容时也要加上:包名.模块名
软件开发规范
# bin目录:存放执行脚本
# conf目录:存放配置文件
# core目录:存放核心逻辑
# db目录:存放数据库文件
# lib目录:存放自定义的模块与包 :既不是内置也不是第三方,比较完善的功能,还和当前项目的相关性不大,通用模块
# log目录:存放日志
实例:项目开发中的引用和思路
项目从 bin目录下 的 start.py 启动,启动是应该导入 核心代码中的 main.py 中的 main函数
#这涉及 模块导入问题;当前工作目录是 在/bin/start.py ,思路是跳到项目最上层目录,再去导入
bin/start.py
import sys
import os
#print(sys.path)
#print(sys.path[0])
#print(__file__) 打印当前路径,__file__可以帮你找到当前路径
project_path=os.path.dirname(os.path.dirname(__file__)) # 返回上级目录
#print(project_path)
sys.path.append(project_path) # 将项目目录添加到sys中
# 接下来就可以导入了
from core import main
if __name__ == '__main__': # 如果直接运行这个脚本,才执行下面的操作
main.home()
------
core/main.py
from core import search
def home():
print("欢迎使用员工查询系统!")
operate_list = ['查询', '修改', '删除', '添加']
for index,item in enumerate(operate_list,1):
print(index,item)
try:
num=int(input("请输入你要操作功能的序号:"))
except :
print("请输入正确的序号!")
if num == 1:
search.select()
------
core/search.py
from conf import settings # search中要去找配置文件
def select():
condition = input('>>>')
# 收到命令要处理一下
# 要到文件中去查
# 要打开文件
# 文件名怎么取????
staff_info = settings.staffinfo
with open(staff_info) as f:
for line in f:
print(line.strip())
------
conf/settings.py
staffinfo=r"F:\PyStudy\daytest\code\staff_info\db\staff_infomation"
安装模块
控制台安装
-
pip3 install requests
pip3 install beautifulsoup4 -
pip3 install 遇到的问题:
在python中Scripts目录下找到pip3
Scripts:脚本(相当于一个仓库) -
找不到内部指令?
方式一:控制台写上完整的路径
python安装路径\Scripts\pip3 install requests方式二:在环境变量加上完整路径
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\Scripts -
版本低?
You are using pip version 10.0.1, however version 19.2.3 is available.
You should consider upgrading via the ‘python -m pip install --upgrade pip’ command.确定是python安装目录后,在控制台直接输入提升升级命令:python -m pip install --upgrade
Python\Scripts\python -m pip install --upgrade 后,提示成功,则升级成功了pip
pycharm上安装模块
- 这种方式安装的模块,只对当前项目有效
- 安装步骤:
pycharm->file->setting->project:当前项目->project interpreter->右边“+”->搜索requests->install package