概述
模块,用一砣代码实现了某个功能的代码集合。一个功能可能由 N 个函数来组成,这些函数写到一个py文件中,那么这个Py文件就是传说中的模块.
模块可将代码归类,让你的代码看着条理清晰,当然还需要你在提前设计程序时的设计思路清晰,更多的调用,慢慢练吧,骚年!
模块使用时的特点:
- 先导入,后使用
- 模块可为目录,也可为py文件
模块分为三类:
- 内置模块
- 第三方模块
- 自定义模块
自定义模块
自定义模块顾名思义就是自己编写的对某功能实现的一些函数集合.
模块的导入
模块导入的方式比较多:
import index #执行py与index在同一目录
from index import func1 #执行py与index在同一目录,func1为index.py中的某个函数
又比如,有某个目录:
|____1.py
|____2.py
|______pycache__
| |____geno.cpython-35.pyc
|____db
|____digui.py
|____geno.py
|____iter_test.py
|____lib
| |______pycache__
| | |____commands.cpython-35.pyc
| |____commands.py
1.py想导入lib/commands.py文件中的东西,commands是一个模块,我们可以这么做:
from lib import commands #导入
commands.func1 #调用func1函数
#也可以这么用
from lib.commands import *
func1 #直接调用
那么问题来了,不同目录之间怎么调用呢?
.
|______init__.py
| |____a
| | |____22.py
| | |______init__.py
| | |______pycache__
| | | |______init__.cpython-35.pyc
| | | |____test.cpython-35.pyc
| | |____test.py
| |____b
| | |____1.py
b/1.py 想调用a/22.py 模块,这就需要添加环境变量来调用了
import sys
sys.path.append('..')
但这么搞是不是有点太low了,来个比较高档点吧:
import sys,os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
为毛这么搞可以?来解释下:
- file 获取当前文件以及所在的位置,但有可能得到的是相对路径
- os.path.abspath() 获取文件的绝对路径
- os.path.dirname() 获取文件的上级目录
这里需要插播一下python自动创建的全局变量:
- file 获取当前文件以及所在的位置,但有可能得到的是相对路径
- name 如果模块被导入,那么__name__的名字就为模块的名字,如果模块是被直接执行,__name__的值为’main’
- main 仅仅是用来检测该文件代码是否是主程序文件,也即非模块。通常可以用来测试模块比如你可以通过检测来执行一些测试用例,但当文件作为模块导入其他程序中时,检测__main__会为False,即里面的代码不会执行
- doc 获取文件的注释
- cached 字节码的路径
- package 一般使用方式:print(xxx.package),显示xxx模块的文件路径
内置模块
sys模块
来看一个比较好玩的进度条吧,装逼器:
import sys,time
def view_bar(num,totle):
rate=num/totle
rate_num=int(rate*100)
r='
%s>%d%%'%('='*num,rate_num)
sys.stdout.write(r)
sys.stdout.flush()
if __name__ == '__main__':
for i in range(101):
time.sleep(0.1)
view_bar(i,100)
sys比较简单,主要用来提供对python解释器的操作.
sys.argv #命令行参数List,第一个元素是程序本身路径
sys.exit(n) #退出程序,正常退出时exit(0)
sys.version #获取Python解释程序的版本信息
sys.maxint #最大的Int值
sys.path #返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform #返回操作系统平台名称
sys.stdin #输入相关
sys.stdout #输出相关
sys.stderror #错误相关
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下为"
",Linux下为"
"
os.pathsep #用于分割文件路径的字符串
os.name #字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示
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所指向的文件或者目录的最后修改时间
os.getlogin() #获取当前登录用户
重点说下os.path.join()的用法:
一般是在拼接路径的时候用的。举个例子
os.path.join(“home”, "me", "mywork")
在Linux系统上会返回
“home/me/mywork"
在Windows系统上会返回
"homememywork"
好处是可以根据系统自动选择正确的路径分隔符"/"或""
之前博客中有写一篇判断文件是否存在的模块,链接在这:
点我点我点我
hashlib
用于加密相关的操作,替代了MD5和SHA,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
看下例子:
import hashlib
obj=hashlib.md5(bytes('asdfasdf',encoding='utf8')) #1
obj.update(bytes('123',encoding='utf8'))
res=obj.hexdigest()
print(res)
1位置有一个'hashlib.md5(bytes('asdfasdf',encoding='utf8'))',干啥用的呢?因为如果碰到撞库攻击的时候,对方会用的密码字典去匹配你的密码,所以我们在前面加上自己的字段,这样生成的md5值肯定和对方的不一样了!
之前博客中有一篇说了下一个密码加密的东西,链接:
点我点我点我
random模块
随机模块,比较简单,不多做说明了.
之前博客中有一篇随机生成验证码的模块,链接在这:
点我点我点我
序列化模块
Python中序列化数据的模块有两个:
- json 用于【字符串】和 【python基本数据类型】 间进行转换
- pickle 用于【字符串】和 【python基本数据类型】 间进行转换
其实无非是load/dump/loads/dumps的应用
json 和 pickle 区别
-
json 更适合夸语言操作,字符串,基本数据类型操作
-
pickle 适合所有类型的序列化 python 操作,pickle 仅适用于 python,2和3可能不兼容
json
通过 json.loads 反序列化时,一定要注意双引号,要与其他语言格式相匹配了
之前博客写过一片json的使用,链接:
点我点我
pickle
大体类似,上个例子吧,需要注意的一点就是二进制文件的读写模式:
import pickle
li=[1,2,3,4,5,'cc']
####pickle.dump(li,open('db','wb'))
r=pickle.dumps(li)
print(r)
res=pickle.loads(r)
print(res)
out:
b'x80x03]qx00(Kx01Kx02Kx03Kx04Kx05Xx02x00x00x00ccqx01e.'
[1, 2, 3, 4, 5, 'cc']
requests模块
Requests 是一个第三方的库,是使用 Apache2 Licensed 许可证的 基于Python开发的HTTP 库,其在Python内置模块的基础上进行了高度的封装,从而使得Pythoner进行网络请求时,变得美好了许多,使用Requests可以轻而易举的完成浏览器可有的任何操作。要比urllib模块强大.
安装很简单: pip3 install requests
配合json可以玩个有意思的天气查询:
import json,requests
response = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=北京')
response.encoding='utf-8'
dic=json.loads(response.text) #text 指 requests生成的内容
print(dic)
out:
{'desc': 'OK', 'data': {'wendu': '20', 'forecast': [{'fengxiang': '无持续风向', 'date': '14日星期二', 'low': '低温 18℃', 'high': '高温 24℃', 'fengli': '微风级', 'type': '雷阵雨'}, {'fengxiang': '无持续风向', 'date': '15日星期三', 'low': '低温 17℃', 'high': '高温 30℃', 'fengli': '微风级', 'type': '多云'}, {'fengxiang': '无持续风向', 'date': '16日星期四', 'low': '低温 20℃', 'high': '高温 33℃', 'fengli': '微风级', 'type': '多云'}, {'fengxiang': '无持续风向', 'date': '17日星期五', 'low': '低温 22℃', 'high': '高温 33℃', 'fengli': '微风级', 'type': '多云'}, {'fengxiang': '无持续风向', 'date': '18日星期六', 'low': '低温 21℃', 'high': '高温 31℃', 'fengli': '微风级', 'type': '多云'}], 'yesterday': {'fx': '无持续风向', 'date': '13日星期一', 'low': '低温 18℃', 'high': '高温 22℃', 'fl': '微风', 'type': '雷阵雨'}, 'city': '北京', 'ganmao': '各项气象条件适宜,无明显降温过程,发生感冒机率较低。', 'aqi': '45'}, 'status': 1000}
time模块
时间相关的操作,有time,datetime两个模块.
python中的时间表示,有三种方式:
- 1970年1月1日之后的秒,即:time.time()
- 2014-11-11 11:11, 即:time.strftime('%Y-%m-%d')
- 结构化时间 是一个元组数据,元组包含了:年、日、星期等... time.struct_time 即:time.localtime()
import time
import datetime
print(time.time()) #返回当前系统时间戳
print(time.ctime()) #输出Tue Jan 26 18:23:48 2016 ,当前系统时间
print(time.ctime(time.time()-86640)) #将时间戳转为字符串格式
print(time.gmtime(time.time()-86640)) #将时间戳转换成struct_time格式
print(time.localtime(time.time()-86640)) #将时间戳转换成struct_time格式,但返回本地时间
print(time.mktime(time.localtime())) #与time.localtime()功能相反,将struct_time格式转回成时间戳格式
time.sleep(4) #常用,用来暂停
print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将struct_time格式转成指定的字符串格式
print(time.strptime("2016-01-28","%Y-%m-%d") ) #将字符串格式转换struct_time格式
################################
print(datetime.date.today()) #输出格式 2016-01-26
print(datetime.date.fromtimestamp(time.time()-864400) ) #2016-01-16 将时间戳转成日期格式
current_time = datetime.datetime.now() #
print(current_time) #输出2016-01-26 19:04:30.335935
print(current_time.timetuple()) #返回struct_time格式
###############################################
"""datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]])"""
print(current_time.replace(2014,9,12)) #输出2014-09-12 19:06:24.074900,返回当前时间,但指定的值将被替换
############################################
str_to_date = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") #将字符串转换成日期格式
new_date = datetime.datetime.now() + datetime.timedelta(days=10) #比现在加10天
new_date = datetime.datetime.now() + datetime.timedelta(days=-10) #比现在减10天
new_date = datetime.datetime.now() + datetime.timedelta(hours=-10) #比现在减10小时
new_date = datetime.datetime.now() + datetime.timedelta(seconds=120) #比现在+120s
具体时间的表示方式:
%Y Year with century as a decimal number.
%m Month as a decimal number [01,12].
%d Day of the month as a decimal number [01,31].
%H Hour (24-hour clock) as a decimal number [00,23].
%M Minute as a decimal number [00,59].
%S Second as a decimal number [00,61].
%z Time zone offset from UTC.
%a Locale's abbreviated weekday name.
%A Locale's full weekday name.
%b Locale's abbreviated month name.
%B Locale's full month name.
%c Locale's appropriate date and time representation.
%I Hour (12-hour clock) as a decimal number [01,12].
%p Locale's equivalent of either AM or PM.
看起来复杂吧,来张图吧,应该就清楚了:
logging模块
logging用于记录日志且线程安全的模块.
日志level的分类:
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
但文件日志记录
import logging
logging.basicConfig(filename='log.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=10)
logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')
logging.log(10,'log')
需要注意一点:只有【当前写等级】大于【日志等级】时,日志文件才被记录
format格式中的一些说明:
属性 | 格式化 | 描述 |
---|---|---|
args | 将参数的元组合并进消息产生消息,或者将字典中对应的值合并为消息 | |
asctime | %(asctime)s | 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 |
created | %(created)f | 当前时间,用UNIX标准的表示时间的浮 点数表示 |
exec_info | 异常信息 | |
filename | %(filename)s | 调用日志输出函数的模块的文件名 |
funcName | %(funcName)s | 调用日志输出函数的函数名 |
levelname | %(levelname)s | 文本形式的日志级别 |
levelno | %(levelno)s | 数字形式的日志级别 |
module | %(module)s | 调用日志输出函数的模块名 |
msecs | %(msecs)d | 创建日志时的毫秒时间 |
message | %(message)s | 用户输出的消息 |
msg | 传入的格式化字符串 | |
name | %(name)s | logger的名字 |
pathname | %(pathname)s | 调用文件的路径 |
process | %(process)d | 调用日志系统的进程ID |
processNmae | %(processNmae) | 进程名字 |
thread | %(thread)d | 线程 |
threadName | %(threadName)s | 线程名称 |
那么多文件的写入日志需要怎么搞呢?
日志如果要模块化时,需要有4个知识点:
- logger 创建一个在应用程序中用到的接口
- handler 处理器,将logger产生的日志,发送给对应的文件
- filter 过滤器,用来将符合条件的日志过滤出来
- formatter 输出前格式化日志,形成你想要的格式的日志
import logging
######## create logger
logger = logging.getLogger('TEST-LOG')
logger.setLevel(logging.DEBUG)
######## create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
######## create file handler and set level to warning
fh = logging.FileHandler("access.log")
fh.setLevel(logging.WARNING)
######## create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
######## add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
######## add ch and fh to logger
logger.addHandler(ch)
logger.addHandler(fh)
调用方式:
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
解释下上面的代码:
- 创建一个logger接口
- 创建显示终端或文件,并设置日志级别
- 创建日志格式标准
- 格式标准添加至显示终端
- 将终端的handler添加至logger
之前博客写过一篇日志处理的模块,链接:
点我点我点我