模块,用一砣代码实现了某个功能的代码集合。

类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合。而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.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())

 

posted on 2017-05-24 15:45  进_进  阅读(578)  评论(0)    收藏  举报