模块,用一砣代码实现了某个功能的代码集合。
类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合。而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.py文件中),一般情况下,一个 .py 文件组成的代码集合就称为一个模块。
如:os 是系统相关的模块;file是文件操作相关的模块
模块分为三种:
- 自定义模块
- 内置模块
- 开源模块
一、模块导入
既然模块导入就是加载一个文件,那么python是如何找到我们要导入的模块所在的目录的呢?
#在当前文件下,导入re和sys模块,导入模块时,是根据系统提供的sys.path进行搜索的 import re import sys for i in sys.path: print(i) """ 执行结果: D:\脚本 D:\脚本 C:\Users\augus\AppData\Local\Programs\Python\Python35-32\python35.zip C:\Users\augus\AppData\Local\Programs\Python\Python35-32\DLLs C:\Users\augus\AppData\Local\Programs\Python\Python35-32\lib C:\Users\augus\AppData\Local\Programs\Python\Python35-32 C:\Users\augus\AppData\Local\Programs\Python\Python35-32\lib\site-packages """
由上面代码执行结果可以看出:模块的搜索是按照:当前目录—python35.zip—DLLS—lib—site-packages依次搜索。若想导入的模块不在这些范围内,又怎么处理呢?
现在自己编写的文件day1.py在"D:\jiaoben"目录下,而我需要导入的模块文件在day2.py在“E:\W”目录下,那如何在day1.py中导入day2.py呢
import sys sys.path.append="E:\W" #这句话的的目的就是在模块搜索路径中加入需导入模块的路径 import day2
1、内置模块:
位于"C:\Users\augus\AppData\Local\Programs\Python\Python35-32\Lib"目录下,也就是说内置模块在python程序的lib目录下。直接导入就行。导入方式:直接导入
import re
import randmon
2、开源模块:
就是我们所说的第三方模块,两种处理方式:
第一种:是用python的pip软件管理工具。(此工具在python中已经自带,在..../python/scripts目录下,如python2.7版本pip没有自带,就需要借助setuptools)。(pip软件管理工具其实就是一个模块库,里面存放了我们常用的模块,这就避免了我们在网上自己寻找模块的麻烦)。
安装前请注意:要先将.../python/scripts导入到环境变量中才能使用pip3命令
安装方式:
pip3 install requests #系统会自动替我们下载并安装
安装完成后:
import requests #安装后再执行就不会报错
第二种:直接下载源码。下载源码其实就是去网站寻找你需要的模块,然后下载并解压。 该方法只能在终端上使用,不能借助python编译工具。以windows的cmd为例:
在cmd中,切换目录到第三方模块的setup.py目录下。直接执行:
python setup.py install #记得加上install才代表要安装这个第三方库
同样,安装完成后:
import requests #直接导入模块就不会有错了
3、自定义模块:

如上:test文件夹中创建的三个.py文件就可以分别成为一个模块。那么问题来了,自己写的模块之间是怎么导入的呢?
自定义模块:是不能单纯的像第三方模块和内置模块那么容易导入。导入方式:
第一种情况:
模块和模块之间在同一个目录下。如下:

想在index模块中导入 extension和commons
import extension,commons
第二种情况:
当前文件和需导入模块不在同一个目录下:

#在index文件中需要导入backend.py from libs import backend
from libs.backend import func #在backend.py文件中导入func()方法
#若在backend.py中导入index.py。最安全的导入方法:
import sys
sys.path.append="....\PycharmProjects\test\libs" #这句话的的目的就是在模块搜索路径中加入需导入模块的路径
import day2
第三种情况:
直接将模块移动到当前目录下,或者移动到内置模块或者第三方模块下。就可以直接导入了
4.导入模块的格式:
主要关注方法调用时的不同
#目录module下,有文件day.py。文件中有func()方法 import module
module.day.func() #这是方法调用
import module.day.func
module.day.func() #这是方法调用
import module.day.func
module.day.func() #这是方法调用
from module import day #推荐方式
day.func()#这是方法调用
from module.day import func
func() #这是方法调用
二、sys
用于提供对python解释器相关的操作
sys.argv #获取命令行参数List,第一个元素是程序本身路径。
#(这条命令只限通过命令行执行:python mode.py 1 2) 执行结果:["mode.py的路径","1","2"] sys.exit(n) #退出程序,正常退出时exit(0) sys.version # 获取Python解释程序的版本信息 sys.maxint #最大的Int值 sys.path # 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 sys.platform # 返回操作系统平台名称 sys.stdout.write('please:') val = sys.stdin.readline()[:-1]
sys.stdout.write('\r') #清屏
练习题:
1、读写用户的输入,根据用户输入,创建一个相应的目录
2、写一个下载的进度条,带有百分比
import sys,os cmd=sys.argv[1] os.mkdir(cmd) #python创建文件夹的命令
import sys,time for i in range(51): #这个位置写51,那么就可以循环到50,那么就相当于百分比可达到100% sys.stdout.write("\r") #清屏 sys.stdout.write("%s%%:%s" %(int(i/50*100),int(i/50*100)*"#")) #要想打印多个相同的字符串,只需要进行相乘就行。 sys.stdout.flush() #刷新内存 time.sleep(0.5)
三、os
用于提供操作系统相关的操作:
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: ('.') os.pardir 获取当前目录的父目录字符串名:('..') os.makedirs('dir1/dir2') 可生成多层递归目录 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() 删除一个文件 os.rename("oldname","new") 重命名文件/目录 os.stat('path/filename') 获取文件/目录信息(包括了文件大小等) os.sep 操作系统特定的路径分隔符,win下为"\\",Linux下为"/" os.linesep 当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" os.pathsep 用于分割文件路径的字符串 os.name 字符串指示当前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 运行shell命令,直接显示 。模拟直接在终端执行shell命令 <可能出现乱码> os.popen(cmd, mode="r", buffering=-1) 运行shell命令<不会出现乱码> 通过os.popen(cmd, mode="r", buffering=-1).read()接受返回值
os.environ 获取系统环境变量 os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) 如果path是绝对路径,返回True os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 #将路径拼接在一起,不需要自己手动加路径符号 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
三、time datatime模块
时间相关的操作,时间有三种表示方式:
- 时间戳 1970年1月1日之后的秒,即:time.time()
- 格式化的字符串 2014-11-11 11:11, 即:time.strftime('%Y-%m-%d')
- 结构化时间 元组包含了:年、日、星期等... time.struct_time 即:time.localtime()
import time print time.time() # 时间戳 1970年1月1日开始计时 unix系统诞生1463840728.7381186 print time.mktime(time.localtime()) #mktime 接收结构化的对象时间 转换为时间戳 1463470373.0 # print(time.asctime(time.localtime())) #返回时间格式"Fri Aug 19 11:14:16 2016", #print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上 # 日期字符串 转成 时间戳 # string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #将 日期字符串 转成 struct时间对象格式 # print(string_2_struct) # struct_2_stamp = time.mktime(string_2_struct) #将struct时间对象转成时间戳 # print(struct_2_stamp) #将时间戳转为字符串格式 # print(time.gmtime(time.time()-86640)) #将utc时间戳转换成struct_time格式 # print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将utc struct_time格式转成指定的字符串格式 #时间加减 import datetime # print(datetime.datetime.now()) #返回 当前时间 2016-08-19 12:47:03.941925 #print(datetime.date.fromtimestamp(time.time()) ) # 时间戳直接转成日期格式 2016-08-19 # print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天 # print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天 # print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时 # print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分 # c_time = datetime.datetime.now() # print(c_time.replace(minute=3,hour=2)) #时间替换
4、pickle 和json
用于序列化的两个模块 。主要功能就是为了实现字符串和python的基础数据类型的转换
- json,用于字符串 和 python数据类型间进行转换 。json输出格式任何语言都能精通。但是不能序列化日期格式
- pickle,pickle输出格式只有python才能识别,但是却能序列化python的所有东西(见python开发[第十六篇])
Json模块提供了四个功能:dumps、dump、loads、load <dump和load只能是文件>
pickle模块提供了四个功能:dumps、dump、loads、load <dump和load只能是文件>
pickle:
import pickle s=[1,2,3] #########dumps和loads##### result=pickle.dumps(s) #将列表转为字节加载到内存中 print(result,type(result)) #执行结果:b'\x80\x03]q\x00(K\x01K\x02K\x03e.' <class 'bytes'> x=pickle.loads(result) #将字节从内存中转换成python的基础数据类型 print(x,type(x)) #执行结果:[1, 2, 3] <class 'list'> #########dump和load###### pickle.dump(s,open(r"db","wb")) #将列表写入到文件中
#这里有很大的一个注意点:从dumps中可以看出来,dumps的结果是字节类型,所以,dump和load时也一样,那么写文件一定要使用字节来操作。
# pickle.dump(s,open(r"db","w")) 是错误的
s=pickle.load(open(r"db","rb")) #从文件中将数据读取出来,然后转换成python的基础数据类型 print(f.tell()) #执行结果:14 print(s,type(s)) #执行结果:[1, 2, 3] <class 'list'>
#为了读取文件内容,也可以如下 f.seek(0) f=open(r"db","rb") n=pickle.loads(f.read()) #也可以先将文件内容加载到内存中,再用loads将数据转换成python的基础数据类型
f.close() print(f.tell()) print(n)
当然也可以如下,从而避免了手动关闭文件:
import pickle data={ 100:{"name":"alex","passwd":"qwe123"}, 101:{"name":"zj","passwd":"qwe123"} } with open("accouts.db","wb") as f: #python中写文件只能是写字符串格式 f.write(pickle.dumps(data))#dumps()就是将一个数据转换成只有python认识的字符串 with open("accouts.db","rb") as f: print(pickle.loads(f.read())) #loads()将从文件读出来的内容转换成原有的格式
json:
import json s=[1,2,3] result=json.dumps(s) print(result,type(result)) #执行结果:[1, 2, 3] <class 'str'> #从这个执行结果可以和pickle形成对比。pickle.dumps()后是生成字节格式,而json是转成字符串 x=json.loads(result) print(x,type(x)) #执行结果:[1, 2, 3] <class 'list'> json.dump(s,open(r"db","w")) #这儿和pickle.dump()形成了对比,请注意两者的不同
#因为dumps结果是字符串,所以写文件时不能以二进制格式来操作 f=open(r"db","r") n=json.loads(f.read()) print(f.tell()) print(n)
最强注意点:
loads 方法 将传过来的字符串(长得像python的字典或者列表数据类型)序列化成字典或列表
注意其调用的对象内部必须是双引号,json不识别单引号,而且,整个字符串必须被单引号或者三个引号引起来,否则报错
s = '{"data":"invilad","status":"1000"}' # 这是json的loads才会认识的字符串
#s = "{'data':'invilad','status':'1000'}" #这是json的loads不能识别的字符串,请引起重视 l = "[1,2,3]" import json ret = json.loads(l) # loads 将形似python数据类型列表或字典的字符串转换成 列表或者字典 print(ret,type(ret))
还有一点需要注意:pickle的dump对应load或者loads。不能使用json来dump,然后pickle再来load或者loads。
,5、request
注意:我们接收的网页请求过来都是字符串或者字节,(不管它表现成python的基本数据类型,还是xml类型,没有通过特定的方式解析前,都只是字符串或者字节) <切记>
from urllib import request f = request.urlopen("http://www.cnblogs.com/") # f = request.urlopen("http://yujuanfudan.blog.163.com/") ret = f.read() print(type(ret)) #执行结果:<class 'bytes'> print(str(ret,encoding="utf-8")) #执行结果:是页面代码的内容
urllib等模块以供Http请求,但是,它的 API 太渣了。所以出现了第三方的http请求模块,如下:
Requests 是使用 Apache2 Licensed 许可证的 基于Python开发的HTTP 库,其在Python内置模块的基础上进行了高度的封装,从而使得Pythoner进行网络请求时,变得美好了许多,使用Requests可以轻而易举的完成浏览器可有的任何操作。
因为request是第三方模块,所以第一步应该是安装该模块
1、安装模块
pip3 install requests
2、发送请求
import requests ret = requests.get('https://github.com/timeline.json') print(ret.url) #执行结果:https://github.com/timeline.json print(ret.text) #直接结果:返回的是该网址的页面内容
3、传递URL参数
有时候,我们的请求地址是这样的:http://httpbin.org/get?user=augus&password=qwe123。在URL地址:http://httpbin.org/get后面的?实际是我们在请求页面的时候需要传入的参数,那么这个参数又该如何灵活传入呢?
import requests
payload = {'key1': 'value1', 'key2': 'value2'} r = requests.get("http://httpbin.org/get", params=payload)
print(r.url) #执行结果:http://httpbin.org/get?key2=value2&key1=value1
4、post 请求
# 1、基本POST实例 import requests payload = {'key1': 'value1', 'key2': 'value2'} ret = requests.post("http://httpbin.org/post", data=payload) print(ret.text) # 2、发送请求头和数据实例 import requests import json url = 'https://api.github.com/some/endpoint' payload = {'some': 'data'} headers = {'content-type': 'application/json'} ret = requests.post(url, data=json.dumps(payload), headers=headers) #如果传入的data不是dict类型,就可以使用json.dumps将数据转为string就可以传入了。 print(ret.text) print(ret.cookies)
更多requests模块相关的文档见:猛戳这里
request同 json 的应用:
import requests,json # ret = requests.get("http://www.baidu.com") ret = requests.get("http://www.weather.com.cn/adat/sk/101010500.html") #模拟浏览器网站 ret.encoding = "utf-8" result = ret.text print(type(result),result) #这个时候返回的是字符串,记住所有接口返回的都是字符串。 n = json.loads(result) #使用json将字符串转为python的基础类型 print(type(n),n)
注:更多接口猛击这里
5、hashlib
用于加密相关的操作,代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
import hashlib # ######## md5 ######## hash = hashlib.md5() # help(hash.update) hash.update(bytes('admin', encoding='utf-8')) print(hash.hexdigest()) print(hash.digest()) ######## sha1 ######## hash = hashlib.sha1() hash.update(bytes('admin', encoding='utf-8')) print(hash.hexdigest()) # ######## sha256 ######## hash = hashlib.sha256() hash.update(bytes('admin', encoding='utf-8')) print(hash.hexdigest()) # ######## sha384 ######## hash = hashlib.sha384() hash.update(bytes('admin', encoding='utf-8')) print(hash.hexdigest()) # ######## sha512 ######## hash = hashlib.sha512() hash.update(bytes('admin', encoding='utf-8')) print(hash.hexdigest())
以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。
import hashlib # ######## md5 ######## hash = hashlib.md5(bytes('898oaFs09f',encoding="utf-8")) #创建md5时传入一个参数,使下面加密的密码变的更加混淆 hash.update(bytes('admin',encoding="utf-8")) print(hash.hexdigest())
python内置还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密
import hmac h = hmac.new(bytes('898oaFs09f',encoding="utf-8")) h.update(bytes('admin',encoding="utf-8")) print(h.hexdigest())
浙公网安备 33010602011771号