今天学习Python中的模块,模块类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合。而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.py文件中),n个.py文件组成的代码集合就称为模块。
模块分为三种:
-
自定义模块
-
第三方模块
-
内置模块
下面就分别就这三种模块的展开学习:
一、自定义模块
1,定义模块,定义模块的场景有三种:
1
2
3
4
5
|
场景 1 、定义的的模块在同一目录下 场景 2 、定义的模块在同一目录的不同子目录下 场景 3 、自定义多个模块 |
2,导入模块
下面就根据上面三种场景分别进行导入,导入的方法如下:
1
2
3
4
5
6
7
|
import module #调用模块,一般调用内置模块或第三方模块 from module import xx #导入某个模块的某个方法 from module import xx as rename #导入模块并定义模块别名 from module import * #导入模块的所有方法 |
导入模块其实就是告诉Python解释器去解释那个py文件,先导入一个py文件,解释器解释该py文件,然后导入一个包,解释器解释该包下的__init__.py文件,
那么我们怎么才能获取导入模块时是根据那个路径作为基准来进行的呢?这里就需要导入内置模块sys的path方法:
1
2
3
4
5
6
|
import sys print (sys.path) #结果: [ 'E:\project\Day5' , 'E:\project' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35\python35.zip' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35\DLLs' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35\lib' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35\lib\site-packages' ] |
如果sys.path路径列表没有你想要的路径,可以通过sys.path.append('路径')添加,具体代码如下:
1
2
3
4
5
6
7
8
|
import sys sys.path.append( 'E:modules' ) print (sys.path) #结果: [ 'E:\project\Day5' , 'E:\project' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35\python35.zip' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35\DLLs' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35\lib' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35' , 'C:\Users\Henry\AppData\Local\Programs\Python\Python35\lib\site-packages' , 'E:\modules' ] |
二、第三方软件
1、下载安装第三方模块
下载安装有两种方式:
1
2
3
4
5
6
7
8
9
10
11
|
#Linux自带的一下管理软件包的命令 yum pip apt - get ..... #去官网下载源码进行安装 解压源码 进入目录 编译源码:Python setup.py build 安装源码:Python setup.py install |
注:在源码安装时要依赖gcc编译和Python开发环境的支持,要先执行:
1
2
|
yum - y install gcc yum - y install python - devel |
模块安装成功后,通过sys.path找到模块的路径,然后在目录中就可以找到刚刚安装的模块。
2、使用导入模块
下面就举一个例子来示范,如果使用和导入第三方模块:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#首先通过pip install requests 安装一个requests模块 #然后导入模块进行使用 import requests #导入requests、json模块 import json reponse.encoding = 'utf-8' dic = json.loads(reponse.text) #将值转换成Python解释的数据类型 print (dic, type (dic)) |
三、内置模块
1、sys模块——用于提供Python解释器相关操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
sys.argv #命令行参数List,第一个元素是程序本身路径 sys.exit(n) #退出程序,正常退成时exit(0) sys.maxsize #最大的Int值 sys.path #返回模块的搜索路径,初始化时使用PYTHONPATH环境变量 sys.platfrom #操作系统平台名称 sys.stdin #输入相关 sys.stdout #输出相关 sys.stderror #错误相关的 import sys sys.stdout.write( 'Hello World!' ) #屏幕输出hello world import sys print ( 'Please enter your name:' ) name = sys.stdin.readline()[: - 1 ] #获取命令行输入 print ( 'Hi,%s' % name) |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import sys import time def view_bar(num,total): rate = float (num) / float (total) rate_num = int (rate * 100 ) r = '
%d%%' % (rate_num) sys.stdout.write(r) #屏幕输出百分比 sys.stdout.flush() #屏幕强制刷新 if __name__ = = '__main__' : for i in range ( 0 , 100 ): time.sleep( 0.1 ) view_bar(i, 100 ) |
2、os模块——用于提供系统级别的操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
os.getcwd #获取当前工作目录,即当前python脚本工作目录路径 os.chdir( "dirnaem" ) #改变当前脚本工作目录;相当于shell下cd os.curdir #返回当前目录:('.') os.pardir #获取当前目录的父目录字符串名('..') os.makedirs( 'dir1/dir2' ) #可生成多层递归目录 os.removedirs( 'dirnaem' ) #若目录为空,则删除,并递归到上级目录,若也为空,删除,以此类推 os.mkdir( 'dirname' ) #创建目录 os.rmdir( 'dirname' ) #删除单级空目录,目录为空则无法删除 os.listdir( 'dirname' ) #列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表的方式打印 os.remove() #删除一个文件 os.rename( "old" , "new" ) #重命名文件/目录 os.stat( 'path/filename' ) #获取文件/目录信息 os.sep #操作系统特定的路径分隔符,win:'\';linux:'/' os.system( 'bash command' ) #运行shell命令,直接显示 os.environ #获取系统环境变量 os.path.abspath(path) #返回path规范化的绝对路径 os.path.split(path) #将path分割成目录和文件名二元组返回 os.path.dirname(path) #返回path的目录。 os.path.basename(path) #返回path最后的文件名 os.path.exists(path) #如果path存在返回True,如果不存在,返回False os.path.isabs(path) #如果path是绝对路径,返回True os.path.isfile(path) #如果path是一个存在的文件,返回True,相反返回Fasle os.path.isdir(path) #如果path是一个存在的目录,返回True,相反 os.path.join(path1[,path2[,....]]) #将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 os.path.getatime(path) #返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) #返回path所指向文件或者目录的最后修改时间 |
3、json、pickle——python中用于序列化的两个模块
json :用于【字符串】和【python基本数据类型】间进行转换
pickle:用于【python特有类型】和【python基本数据类型】间的转换
Json模块提供了四个功能:dumps、loads、dump、load,下面介绍一下具体用法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import json li = { 'k1' : 123 } result = json.dumps(li) #将Python基本数据类型转化成字符串形式 print (result, type (result)) 结果: { "k1" : 123 } < class 'str' > li = '{"k1":123}' #注意:反序列化时,内部一定要使用双引号 result = json.loads(li) #将python字符串形式转化成基本数据类型 print (result, type (result)) 结果: { 'k1' : 123 } < class 'dict' > { 'k1' : 123 } < class 'dict' > |
1
2
3
4
5
6
7
8
9
|
import json li = [ 11 , 22 , 33 ] json.dump(li, open ( 'db' , 'w' )) #将列表dump持久化到一个文件里 li = json.load( open ( 'db' , 'r' )) #将列表从文件中读取出来 print (li, type (li)) 结果: [ 11 , 22 , 33 ] < class 'list' > |
同样pickle也提供了四个功能:dumps、loads、dump、laod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import pickle li = [ 11 , 22 , 33 ] a = pickle.dumps(li) #dumps、loads都是在内存中进行转换 print (a) 结果: b 'x80x03]qx00(Kx0bKx16K!e.' result = pickle.loads(a) print (result) 结果: [ 11 , 22 , 33 ] |
1
2
3
4
5
6
7
8
9
|
#从上面的例子可以看出,pickle转换是将Python的基本类型转换成二进制格式,那么我们存文件时也要以二进制的格式存储 li = [ 11 , 22 , 33 ] a = pickle.dump(li, open ( 'db' , 'wb' )) #以二进制文件保存到文件 result = pickle.load(li, open ( 'db' , 'rb' )) print (result) 结果: [ 11 , 22 , 33 ] |
下面总结一下json和pickle的区别:
Json: 更适合跨语言,字符串,只能处理Python的基本数据类型
Pickle:只用于Python做所有类型的序列化,仅适用于Python,上下版本有可能不兼容
4、time模块——时间相关的操作
时间相关的操作,时间有三种表示方式:
-
时间戳 1970年1月1日之后的秒,即:time.time()
-
格式化的字符串 2016-06-09 11:25,即:time.strftime('%Y-%m-5d')
-
结构化时间 元组包含了:年、日、星期等......time.struct_time 即:time.localtime()
下面具体介绍一下time模块的一些方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import time print (time.time()) #返回从1970年到现在的时间戳 1465447994.0811183 print (time.ctime()) #输出当前系统时间 Thu Jun 9 12:53:48 2016 print (time.ctime(time.time() - 86400 )) #将时间戳转换为字符串格式 Wed Jun 8 12:56:53 2016 print (time.gmtime(time.time() - 86400 )) #将时间戳UTC转换成struct_time格式 print (time.localtime(time.time() - 86400 )) #将本地时间的时间戳转换成struct_time格式: print (time.mktime(time.localtime())) #将struct_time格式转换回时间戳格式 1465448495.0 print (time.strftime(' % Y_ % m_ % d % H: % M: % S',time.gmtime())) #将struct_time格式转换成指定的字符串格式 2016-06-09 05:03:22 print (time.strptime( "2016-06-09" , "%Y-%m-%d" )) #将字符串格式转换成struct_time格式 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import datetime print (datetime.date.today) #输出格式2016-06-09 print (datetime.date.fromtimestamp(time.time() - 86400 )) #输出昨天的时间 current_time = datetime.datetime.now() print (current_time) #输出2016-06-09 13:09:28.271793 print (current_time.timetuple()) #返回struct_time格式 print (current_time.repace( 2015 , 5 , 20 )) #输出2015-05-20 13:11:34.505876,返回当前时间,但指定的值将被替换 str_to_date = datetime.datetime.strptime( "21/11/06 16:30" , "%d/%m/%y %H:%M" ) #将字符串转换成日期格式 2006-11-21 16:30:00 new_date = datetime.datetime.now() + datetime.timedelta(day = 10 ) #比现在加十天 new_date = datetime.datetime.now() + datetime.timedelta(hours = - 10 ) #比现在减10小时 print (new_date) 2016 - 06 - 19 13 : 18 : 14.567043 #10天以后 2016 - 06 - 09 03 : 18 : 36.311825 #10小时之前 |
下面是时间格式化的占位符的表示方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
% 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. |
5、logging——用于简便记录日志且线程安全的模块
很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还有错误、警告等信息输出,Python的logging模块就提供了标准的
日志接口,可以通过它存储各种格式的日志。
logging的日志可以分为debug(),info(),warning(),error(),critical() 5个级别
这几个级别的严重性从低到高依次为DEBUG < INFO < WARNING < ERROR < CRITICAL
下面具体介绍一下模块的使用:
1
2
3
4
5
6
7
8
9
|
import logging logging.warning( "user[jack]attempted wrong pasword more than 3 times" ) logging.critical( 'server is down' ) #终端会输出结果: WARNING:root:user[jack]attempted wrong pasword more than 3 times CRITICAL:root:server is down |
上面的例子是将结果输出到屏幕上,如果我想将日志写到文件里,如何操作呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import logging logging.basicConfig(filename = 'error.log' ,level = logging.INFO) logging.debug( 'This message should go to the log fie' ) logging.info( 'So should this' ) logging.warning( 'And this too' ) #结果: #error.log里有内容添加进来 INFO:root:So should this WARNING:root:And this,too #上面logging.INFO意思是,把日志记录级别设置为INFO,只有是INFO级别或者比INFO级别更高的日志才会被记录到文件中,在这个例子中第一条DEBUG的日志就不会被记录,如果想记录将INFO 修改成DEBUG |
上面的例子里发现文件里没有记录时间,下面就修改一下代码加上时间格式:
1
2
3
4
5
6
7
|
import logging logging.basicConfig( format = '%(asctime)s %(message)s' , datefmt = '%m/%d/%Y %I:%M:%S %p' ) logging.warning( 'is when this event was logged.' ) #结果: 06 / 09 / 2016 01 : 43 : 13 PM is when this event was logged. |
下面介绍一下logging.basicConfig函数的各个参数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
filename #指定日志文件名 filemode #和file函数意义相同,指定日志文件的打开模式,'w'或'a' format #指定输出的格式和内容,format可以输出很多有用信息,如上例所示: % (levelno)s #打印日志级别的数值 % (levelname)s #打印日志级别名称 % (pathname)s #打印当前执行程序的路径,其实就是sys.argv[0] % (filename)s #打印当前执行程序名 % (funcName)s #打印日志的当前函数 % (lineno)d #打印错误日志的行号 % (asctime)s #打印日志的时间 % (thread)d #打印线程ID % (threadName)s #打印线程名称 % (process)d #打印进程ID % (message)s #打印日志信息 datefmt #指定时间格式,默认为logging.strftime() #用法:datefmt = '%a,%d %b %Y %H:%M:S' level #设置日志级别,默认为logging.WARNING stream #指定将日志的输出流,可以指定输出到sys.stderr、sys.stdout或者文件,默认输出到sts.stderr |
如果想同时把log打印在屏幕和日志里,就需要在掌握一些复杂的知识:
-
logger:提供了应用程序可以直接使用的接口;
-
handler:将(logger创建的)日志记录发送到合适的目的输出;
-
filter:提供细度设备来决定输出那条日志记录;
-
formatter:决定日志记录的最终输出格式。
下面就分别介绍一下上面这四种方法在实际工作中的应用:
1、Logger
Logger输出信息之前必须获得一个Logger(如果没有显示的获取则自动创建并使用root Logger)。
这里所说的Logger就是程序的执行用户,默认是root执行,可以指定zabbix、nginx等用户。
logger = logging.getLogger() 返回一个默认的Logger也即root Logger,并应用默认的日志级别WARNING、Handler和Formatter设置
logging.setLevel(level) 指定最低的日志级别,可用日志级别有:logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、 logging.CRITICAL.
注意:此处定义为全局的日志级别, 全局日志级别是一个基调,下面局部日志级别只能比全局日志级别高或者相等才能正常输出,不能比全局日志级别低。
1
2
3
4
|
import logging logger = logging.getLogger( 'mylogger' ) #定义程序的执行用户 logger.setLevel(logging.DEBUG) #定义全局日志级别 |
2、Handler
Handler对象负责发送相关的信息到指定目的地,有几个常用的Handler方法:
-
Handler.setLevel(level): 指定日志级别,低于全局日志级别的日志将被忽略
-
Handler.setFormatter():给这个handler选择一个Formatter
-
Handler.addFilter(filt)、Handler.remove(filt):新增或删除一个filter对象
可以通过addHandler()方法为Logger添加多个Handler:
1
2
|
logger.addHandler( '输出到屏幕' ) logger.addHandler( '输出到文件' ) |
下面列举几种定义Handler输出的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
logging.StreamHandler #向终端输出日志信息 logging.FileHandler #向文件是输出日志信息 logging.handlers.RotatingFileHandler #类似上面的FileHandler,但是它可以管理文件大小;当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建一个新的同名日志文件输出 logging.handlers.TimedRotatindFileHandler #和RotatindFileHandler类似,不过它没有通过判断文件大小来决定何时重新创建文件,而是间隔一定时间就自动创建新的日志文件 logging.handlers.SocketHandler # 使用TCP协议,将日志信息发送到网络 logging.handlers.DatagramHandler #使用UDP协议,将日志信息发送到网络 logging.handlers.SysLogHandler #日志输出到syslog logging.handlers.SMTPHandler #远程输出日志到邮件地址 logging.handlers.MemoryHandler #日志输出到内存中的指定buffer logging.handlers.HTTPHandler #通过'GET'或'POST'远程输出到HTTP服务器 更多详细使用方法,请参考官网: https: / / docs.python.org / 2 / library / logging.handlers.html |
3、Formatter
Formatter对象设置日志信息最后的规则、结构和内容,默认时间格式为%Y-%m-%d %H:%M:%S
1
|
formatter = logging.Formatter( '%(asctime)s - %(name)s' - % (levelname)s - % (message)s') |
Formatter参数中用到的字符串的占位符和logging.basicConfig()函数用到的相同。
4、Filter
限制只有满足过滤规则的日志才会输出,比如我们定义了filter=logging.Filter('a,b,c'),并将这个Filter添加给了一个Handler上,则使用该Handler的Logger中只有名字带有a,b,c前缀的Logger才会输出其日志。
上面分别介绍了一下logging模块的高级用法中的Logger、Handler、Formatter和Filter,下面通过一个小例子把几个用法串到一起使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
import logging #create logger logger = logging.getLogger( 'haifeng' ) #指定程序执行的用户名 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) #日志级别为WARING #create formatter formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(lineno)s - %(message)s' ) #定义日志内容的格式 #add formatter to ch and fh ch.setFormater(formatter) #定义屏幕输出按照上面定义的日志格式 fh.setFormatter(formatter) #文件输出也是这个格式 #add ch and fh to logger logger.addHandler(ch) #添加Handler打印到终端上的方式到logger logger.addHandler(fh) #添加Handler打印到文件中的方式到logger #'application' code logger.debug( 'debug message' ) logger.info( 'info message' ) logger.warn( 'warn message' ) logger.error( 'error message' ) logger.critical( 'critical message' ) |
今天模块就介绍到这里,后续还有一些常用的模块在陆续补充,请大家持续关注。