模块

模块(modules)的概念:

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)。

使用模块有什么好处?

最大的好处是大大提高了代码的可维护性。

其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。

所以,模块一共三种:

  • python标准库
  • 第三方模块
  • 应用程序自定义模块

另外,使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。

 

 模块导入的方法:

存在以下两个.py文件,都为于F:\\code\\day18路径下:

calculate.py



1 print('ok')
2 
3 x = 3
4 def add(x,y):
5     return x+y
6 
7 def sub(x,y):
8     return x-y



 

bin.py

1.import语句:



1 import sys
 2 
 3 #搜索路径:
 4 print(sys.path)  #['F:\\code\\day18', 'F:\\code', 'E:\\soft_install\\python\\python3.5\\python35.zip', 'E:\\soft_install\\python\\python3.5\\DLLs', 'E:\\soft_install\\python\\python3.5\\lib', 'E:\\soft_install\\python\\python3.5', 'E:\\soft_install\\python\\python3.5\\lib\\site-packages']
 5 
 6 import calculate  #作用是解释器通过搜索路径找到calculate.py模块后,将calculate.py所以代码解释完成后(即执行模块)赋值给calculate对象,此时calculate.py里的所有方法以及变量都要通过calculate对象来调用。
 7 print(calculate.add(1,2))  #调用calculate.py模块的add方法
 8 # 输出:
 9 # ok
10 # 3
11 
12 print(x)  #报错:NameError: name 'x' is not defined
13 print(calculate.x)  #3



2.from....import....语句:



1 #from calculate import add  也可以只导入模块的部分方法,则模块中的其它方法将无法调用
2 print(add(1,2))  #调用calculate.py模块的add方法
3 # 输出:
4 # ok
5 # 3
6 
7 print(sub(1,2))  #报错,NameError: name 'sub' is not defined



3.from....import* 语句:



1 from calculate import *  
 2 print(add(1,2)) #和1的区别是无需通过calculate.add()来调用函数
 3 print(sub(1,2))
 4 print(x)  
 5 
 6 # 输出:
 7 # ok
 8 # 3
 9 # -1
10 # 3



这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。大多数情况, Python程序员不使用这种方法,因为引入的其它来源的命名,很可能覆盖了已有的定义。

4.运行本质:



1 #1 import calculate
2 #2 from calculate import add



无论1还是2,首先通过sys.path找到calculate.py,然后执行calculate.py脚本(全部执行),区别是1会将calculate这个变量名加载到名字空间,而2只会将add这个变量名加载进来。

5.自定义方法名



1 from calculate import add as plus
2 
3 add(1,2)  #报错
4 plus(1,2) #这是需要通过plus来调用方法



 

 

包(package)

作用:如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)。举个例子,一个abc.py的文件就是一个名字叫abc的模块,一个xyz.py的文件就是一个名字叫xyz的模块。现在,假设我们的abcxyz这两个模块名字与其他模块冲突了,于是我们可以通过包来组织模块,避免冲突;

注意:每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录(文件夹),而不是一个包。__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是对应包的名字;调用包就是执行包下的__init__.py文件(即import PACKGE 即执行包下的__init__.py文件)

 

  • 存在如下目录结构:

python模块也是对象吗 python中模块的意义_shell

 

 在bin.py模块中调用web下的logger模块:



1 from web import logger
2 logger.logger()   #在bin.py模块中就可以实现调用web下logger模块中的方法了



 

  •  存在如下目录结构:

python模块也是对象吗 python中模块的意义_json_02

 

在bin.py模块中调用web下web2下的logger模块:



1 from web.web2 mport logger
2 logger.logger()



只调用logger下的某些方法:



1 from web.web2.logger import logger  #调用logger模块下的logger方法
2 logger.logger()



 

  • BASE_DIR引入:

存在如下目录结构:

python模块也是对象吗 python中模块的意义_json_03

main.py:



1 #import logger   #如果这样写,在bin.py中调用main方法时会报无法找到logger的错误,应该改成如下的方式
2 from module import logger 
3 def main:
4     logger.logger()



 

 logger.py



1 def logger:
2     print('logger')



 

如果修改bin.py是程序的入口,在bin.py中如何调用main.py中的main函数?

bin.py



1 from module import main
2 main.main()  #这句话类似于将main方法中的所有代码复制至该模块(bin.py)下



注意:bin.py在pycharm中可以正常执行,因为在pycharm中在sys.path中将包bin的父目录的路径也添加到搜索路径,所以在pycharm中可以搜索到module;但是再命令行下将报错(因为在bin.py模块下无法找到module包)。

解决:

__file__:获取程序的相对路径,如

print(__file__)  #输出bin.py (在pycharm中打印显示时会将该相对路径转化为绝对路径,其他环境中还是相对路径)

print(os.path.abspath(__file__)) # C:\\Users\\Administrator\\PycharmProjects\\ATM\\bin  (根据相对路径找到绝对路径)

BASE_DIR=(os.path.abspath(os.path.abspath(__file__)))  #C:\\Users\\Administrator\\PycharmProjects\\ATM

优化后的bin.py的代码如下:将程序移植到任何环境下都能执行



1 import sys,os
2 BASE_DIR=(os.path.abspath(os.path.abspath(__file__))) 
3 sys.path.append(BASE_DIR)
4 
5 from module import main
6 
7 main.main()



 

if __name__ =='__main__':

如果我们是直接执行某个.py文件的时候,在该文件中”__name__ == '__main__'“是True,但是我们如果从另外一个.py文件通过import导入该文件的时候,这时__name__的值就是我们这个py文件的名字而不是__main__;这个功能还有一个用处:调试代码的时候,在”if __name__ == '__main__'“中加入一些我们的调试代码,我们可以让外部模块调用的时候不执行我们的调试代码,但是如果我们想排查问题的时候,直接执行该模块文件,调试代码能够正常运行!

例子:

存在以下目录结构:

python模块也是对象吗 python中模块的意义_shell_04

foo.py代码如下:功能模块

def hello:

    print('hello')

hello()   #调试代码,单独执行foo.py时会执行hello()方法,外部调用foo模块时也会执行hello()方法

bin.py代码如下:调用模块

import foo

foo.hello()

输出:输出了两次hello

hello

hello

优化:

foo.py代码如下:

def hello:

    print('hello')

#print(__main__)   在该模块下执行输出的是__main__,则if __name__='__main__'就为True,就会执行调试代码;在模块调用时结果为foo(即为模块名),则在模块调用时if __name__!='__main__',则就不会执行调试代码

if __name__='__main__':

    hello()   #调试代码,单独执行foo.py时会执行hello()方法,外部调用foo模块时将不会执行hello()方法

bin.py代码如下:调用模块

import foo

foo.hello()

输出:只输出一次hello

hello

 

time模块



1 import time
 2 #print(help(time))  查看帮助
 3 
 4 print(time.time())    #1517193182.0534253   时间戳(s),unix诞生以来开始计算
 5 time.sleep(3)         #休眠3s
 6 print(time.clock())   #7.551609587825597e-07  计算cpu执行时间(不包括上面的3s)
 7 print(time.gmtime())  #结构化时间:time.struct_time(tm_year=2018, tm_mon=1, tm_mday=29, tm_hour=2, tm_min=36, tm_sec=5, tm_wday=0, tm_yday=29, tm_isdst=0) 即UTC(世界标准)时间,和北京时间差8h
 8 print(time.localtime())  #本地时间:time.struct_time(tm_year=2018, tm_mon=1, tm_mday=29, tm_hour=10, tm_min=45, tm_sec=10, tm_wday=0, tm_yday=29, tm_isdst=0)
 9 
10 #print(time.strftime(format,p_tuple))
11 print(time.strftime("%Y-%m-%d %H:%M:%S" ))  #字符串时间即自定义格式输出日期 2018-01-29 10:55:02
12 struct_time=time.localtime()
13 print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))  #将结构化时间以字符串时间输出:2018-01-29 10:58:51
14 
15 #time.strptime(string,format)  将字符串时间以结构化时间输出
16 print(time.strptime("2018-01-29 10:58:51","%Y-%m-%d %H:%M:%S"))  #time.struct_time(tm_year=2018, tm_mon=1, tm_mday=29, tm_hour=10, tm_min=58, tm_sec=51, tm_wday=0, tm_yday=29, tm_isdst=-1)
17 #取某个时间值:
18 a=time.strptime("2018-01-29 10:58:51","%Y-%m-%d %H:%M:%S")
19 print(a.tm_hour)   #10
20 print(a.tm_mon)    #1
21 
22 #time.ctime(seconds)
23 print(time.ctime())  #取当前时间:Mon Jan 29 11:11:09 2018
24 print(time.ctime(234566))  #将给定的时间以看得懂的方式输出(unix诞生以来的时间开始计算)
25 
26 #time.mktime(p_tuple)
27 a=time.localtime()
28 print(time.mktime(a))  #将本地时间转化为时间戳:1517195833.0



 

 

datatime模块



1 import datetime
2 print(datetime.datetime.now())   #2018-01-29 11:20:48.342246



 

 

random模块



1 import random
 2 print(random.random())  #取0-1内的随机数
 3 print(random.randint(1,8))  #1-8内的随机数,包括8
 4 print(random.choice("hello")) #在给定的字符串选取随机数
 5 print(random.choice([1,2,3,4,5])) #也可以放列表
 6 print(random.sample([1,2,[3,4]],2)) #在序列中随机选2个,[2, [3, 4]]
 7 print(random.randrange(1,10))  #取1-10的数,不包括10
 8 
 9 
10 #生成随机验证码
11 import random
12 checkcode = ''
13 for i in range(4):
14     current = random.randrange(0,4)
15     if current != i:
16         temp = chr(random.randint(65,90))
17     else:
18         temp = random.randint(0,9)
19     checkcode += str(temp)
20 print checkcode



 

 

os模块

提供对操作系统进行调用的接口。

r:以字符原意思输出。



1 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径;
 2 os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd ;os.chdir(r'F:\code')
 3 os.curdir  返回当前目录: ('.')
 4 os.pardir  获取当前目录的父目录字符串名:('..')
 5 os.makedirs('dirname1/dirname2')    可生成多层递归目录;os.makedirs(r'abc\lriwu\alen')
 6 os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推  ;s.removedirs(r'abc\lriwu\alen')
 7 os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
 8 os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
 9 os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
10 os.remove()  删除一个文件
11 os.rename("oldname","newname")  重命名文件/目录
12 os.stat('path/filename')  获取文件/目录信息    os.stat('path/filename').st_size   获取文件大小,返回值是int类型
13 os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
14 os.linesep    输出当前平台使用的行终止符,win下为"\r\n",Linux下为"\n"
15 os.pathsep    输出用于分割文件路径的字符串;windows:';'  linux:':'
16 os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
17 os.system("bash command")  运行shell命令,直接显示
18 os.environ  获取系统环境变量
19 os.path.abspath(path)  返回path规范化的绝对路径;print(os.path.abspath('./os.py'))
20 os.path.split(path)  将path分割成目录和文件名二元组返回
21 os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
22 os.path.basename(path)  返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
23 os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
24 os.path.isabs(path)  如果path是绝对路径,返回True
25 os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
26 os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
27 os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
28 os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
29 os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间



 

 

sys模块



1 sys.argv           命令行参数List,第一个元素是程序本身文件名
2 sys.exit(n)        退出程序,正常退出时exit(0)
3 sys.version        获取Python解释程序的版本信息
4 sys.maxint         最大的Int值
5 sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
6 sys.platform       返回操作系统平台名称
7 sys.stdout.write('please:')
8 val = sys.stdin.readline()[:-1]



 

 

hashlib模块

用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法;



1 import hashlib
 2  
 3 m = hashlib.md5()
 4 m.update("Hello".encode('utf8')) #python3中,内存中的字符串都是unicode类型,update参数一定需要接收bytes类型,所以需要encode转换(因为python3中只有bytes和str两种数据类型)
 5 m.update("It's me".encode('utf8')) 
 6 print(m.digest()) #2进制格式hash   b']\xde\xb4{/\x92Z\xd0\xbf$\x9cR\xe3Br\x8a'
 7 print(len(m.hexdigest())) #16进制格式hash 5ddeb47b2f925ad0bf249c52e342728a
 8 
 9 
10 #加密过程等同于:
11 m2 = hashlib.md5()
12 m2.update("HelloIt's me".encode('utf8')) 
13 print(len(m2.hexdigest())) #16进制格式hash 5ddeb47b2f925ad0bf249c52e342728a
14 
15 
16 
17 
18 import hashlib
19  
20 # ######## md5 ########
21  
22 hash = hashlib.md5()
23 hash.update('admin')
24 print(hash.hexdigest())
25  
26 # ######## sha1 ########
27  
28 hash = hashlib.sha1()
29 hash.update('admin')
30 print(hash.hexdigest())
31  
32 # ######## sha256 ########
33  
34 hash = hashlib.sha256()
35 hash.update('admin')
36 print(hash.hexdigest())
37  
38  
39 # ######## sha384 ########
40  
41 hash = hashlib.sha384()
42 hash.update('admin')
43 print(hash.hexdigest())
44  
45 # ######## sha512 ########
46  
47 hash = hashlib.sha512()
48 hash.update('admin')
49 print(hash.hexdigest())



 

logging模块

1.简单应用



1 import logging  
 2 logging.debug('debug message')  
 3 logging.info('info message')  
 4 logging.warning('warning message')  
 5 logging.error('error message')  
 6 logging.critical('critical message')  
 
 
 
 #输出
 WARNING:root:warning message
 ERROR:root:error message
 CRITICAL:root:critical message



 

 可见,默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默认的日志格式为日志级别:Logger名称:用户输出消息。

 

2.灵活配置日志级别,日志格式,输出位置(文件输出和标准输出只能选一种)



1 import logging  
 2 logging.basicConfig(level=logging.DEBUG,  
 3                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
 4                     datefmt='%a, %d %b %Y %H:%M:%S',  
 5                     filename='/tmp/test.log',  
 6                     filemode='w')  
 7   
 8 logging.debug('debug message')  
 9 logging.info('info message')  
10 logging.warning('warning message')  
11 logging.error('error message')  
12 logging.critical('critical message')
 
 
 
 #查看输出:
 cat /tmp/test.log 
 Mon, 05 May 2014 16:29:53 test_logging.py[line:8] DEBUG debug message
 Mon, 05 May 2014 16:29:53 test_logging.py[line:9] INFO info message
 Mon, 05 May 2014 16:29:53 test_logging.py[line:10] WARNING warning message
 Mon, 05 May 2014 16:29:53 test_logging.py[line:11] ERROR error message
 Mon, 05 May 2014 16:29:53 test_logging.py[line:12] CRITICAL critical message



 

可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。(a:追加写;w:覆盖写)

  注意:如果没有指定filename和filemode,默认将日志打印到了标准输出中。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的默认日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open('test.log','w')),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。

format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息

 

3.logger对象

 上述几个例子中我们了解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical() 分别用以记录不同级别的日志信息;logging.basicConfig() 用默认日志格式为日志系统建立一个默认的流处理器:设置基础配置(如日志级别等)并加到root logger中,这几个是logging模块级别的函数;另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)

先看一个最简单的过程:



1 import logging
 2 #创建一个日志(logger)对象
 3 logger = logging.getLogger()
 4 
 5 # 创建一个handler即文件输出流对象,用于写入日志文件
 6 fh = logging.FileHandler('test.log')
 7 
 8 # 再创建一个handler即标准输出流对象,用于输出到控制台
 9 ch = logging.StreamHandler()
10 
11 #日志格式对象
12 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
13 
14 fh.setFormatter(formatter)  #为文件输出设置日志格式
15 ch.setFormatter(formatter)  #为标准输出设置日志格式
16 
17 #通过addHandler为logger添加文件输出对象和标准输出对象
18 logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
19 logger.addHandler(ch)
20 #logger1.setLevel(logging.DEBUG)   设置输出日志级别,不指定默认是warnning
21 logger.debug('logger debug message')
22 logger.info('logger info message')
23 logger.warning('logger warning message')
24 logger.error('logger error message')
25 logger.critical('logger critical message')



 

输出:



#控制台输出
2018-01-30 09:53:10,887 - root - WARNING - logger warning message
2018-01-30 09:53:10,887 - root - ERROR - logger error message
2018-01-30 09:53:10,887 - root - CRITICAL - logger critical message



#文件输出
cat test.log
2018-01-30 09:53:10,887 - root - WARNING - logger warning message
2018-01-30 09:53:10,887 - root - ERROR - logger error message
2018-01-30 09:53:10,887 - root - CRITICAL - logger critical



 

 流程图:

python模块也是对象吗 python中模块的意义_字符串_05

 

4.应用




python模块也是对象吗 python中模块的意义_字符串_06

python模块也是对象吗 python中模块的意义_shell_07

1 import os
 2 import time
 3 import logging
 4 from config import settings
 5 
 6 
 7 def get_logger(card_num, struct_time):
 8 
 9     if struct_time.tm_mday < 23:
10         file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon, 22)
11     else:
12         file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon+1, 22)
13 
14     file_handler = logging.FileHandler(
15         os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name),
16         encoding='utf-8'
17     )
18     fmt = logging.Formatter(fmt="%(asctime)s :  %(message)s")
19     file_handler.setFormatter(fmt)
20 
21     logger1 = logging.Logger('user_logger', level=logging.INFO)
22     logger1.addHandler(file_handler)
23     return logger1


View Code


 

 

 ConfigParser模块

常用配置文件的格式如下:



1 [DEFAULT]
 2 ServerAliveInterval = 45
 3 Compression = yes
 4 CompressionLevel = 9
 5 ForwardX11 = yes
 6   
 7 [bitbucket.org]
 8 User = hg
 9   
10 [topsecret.server.com]
11 Port = 50022
12 ForwardX11 = no



使用python生成一个这样的文档:



1 import configparser
 2 
 3 config = configparser.ConfigParser()   #生成一个文件操作句柄
 4 config["DEFAULT"] = {'ServerAliveInterval': '45',
 5                      'Compression': 'yes',
 6                      'CompressionLevel': '9'}
 7 
 8 config['bitbucket.org'] = {}
 9 config['bitbucket.org']['User'] = 'hg'
10 config['topsecret.server.com'] = {}
11 topsecret = config['topsecret.server.com']
12 topsecret['Host Port'] = '50022'  # mutates the parser
13 topsecret['ForwardX11'] = 'no'  # same here
14 config['DEFAULT']['ForwardX11'] = 'yes'
15 with open('example.ini', 'w') as configfile:   #创建文件
16     config.write(configfile)



 

 

增删改查操作:



1 import configparser
 2 
 3 config = configparser.ConfigParser()
 4 #---------------------------------------------查
 5 print(config.sections())   #[]
 6 config.read('example.ini')   #关联文件
 7 print(config.sections())    #['bitbucket.org', 'topsecret.server.com'] 即打印字段,default是默认字段,不会显示出来
 8 print(config.defaults())    #OrderedDict([('compression', 'yes'), ('compressionlevel', '9'), ('serveraliveinterval', '45'), ('forwardx11', 'yes')]) 查看default字段下的所有属性以及属性值
 9 print(config.items('bitbucket.org'))  #[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')] 查看非default字段下的所有属性以及属性值
10 print(config.options('bitbucket.org'))#['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11'] 查看字段下的属性
11 print('bytebong.com' in config)# False   查看配置文件中是否有该字段
12 print(config.has_section('bitbucket.org'))  #查看配置文件中是否有该字段
13 print(config['bitbucket.org']['User']) # hg   查看属性值
14 
15 for key in config:
16     print(key)
17 # 输出:打印config下的所有字段
18 # DEFAULT
19 # bitbucket.org
20 # topsecret.server.com
21 
22 
23 for key in config['bitbucket.org']:
24     print(key)
25 # 输出:bitbucket.org字段下的属性以及default字段下的属性
26 # user
27 # compression
28 # compressionlevel
29 # serveraliveinterval
30 # forwardx11
31 
32 #---------------------------------------------删,改,增
33 
34 #删除字段
35 config.remove_section('topsecret.server.com')
36 
37 #添加字段
38 config.add_section('yuan')
39 
40 #修改属性值
41 config.set('bitbucket.org','user','lriwu')
42 
43 #删除键值对
44 config.remove_option('bitbucket.org','user')
45 
46 
47 (config.write(open('r.cfg', "w")))  #最后这句语句是必须的



 

 

re模块

正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模块被编译成一系列的字节码,然后由C 编写的匹配引擎执行。

作用:字符串提供的方法是完全匹配,无法实现模糊匹配,所以引入正则的原因是可以实现模糊匹配。

 

字符匹配(普通字符,元字符):

1.普通字符:字符串提供的方法是完全匹配,无法实现模糊匹配。



1 import re
2 re.findall('w\w{2}l', 'hello world')  #['worl']  模糊匹配
3 re.findall('alex','yuanaleSxalexwupeiqi')   #['alex']  精确匹配(如果只实现这一功能,使用字符串的方法就可以了)



 

2.元字符:可以实现模糊匹配

  • 元字符之. ^ $ * + ? { }
1 import re
 2 
 3 #'.':匹配任意字符一次(不能匹配换行符)
 4 ret = re.findall('a..in', 'helloalvin')
 5 print(ret)  # ['alvin']
 6 
 7 #'^':行首匹配
 8 ret = re.findall('^a...n', 'alvinhelloawwwn')
 9 print(ret)  # ['alvin']
10 
11 #'$':行尾匹配
12 ret = re.findall('a...n$', 'alvinhelloawwwn')
13 print(ret)  # ['awwwn']
14 
15 #'*':即匹配前面的字符[0,+oo]次
16 ret = re.findall('abc*', 'abcccc')
17 print(ret)  # ['abcccc']   #贪婪匹配
18 ret = re.findall('abc*', 'ab')
19 print(ret)  # ['ab']   #匹配0次例子
20 
21 #'+':匹配前面的字符[1,+oo]次即匹配前面的字符至少一次
22 ret = re.findall('abc+', 'abccc')
23 print(ret)  # ['abccc']  #贪婪匹配
24 
25 #'?':匹配前面的字符[0,1]次
26 ret=re.findall('abc?','abccc')#[0,1]
27 print(ret)#['abc']  #贪婪匹配
28 ret = re.findall('a?b', 'aaaabhghabfb')
29 print(ret)  # ['ab','ab','b']
30 
31 
32 ret = re.findall('abc{1,4}', 'abccc')  #匹配前面的1-4次都行
33 print(ret)  # ['abccc']  贪婪匹配
34 ret = re.findall('a{5}b','aaaaab')  #aaaaab  匹配前面的5次



注意:前面的*,+,?等都是贪婪匹配,也就是尽可能多次匹配,后面加?号使其变成惰性匹配即按照最少的进行匹配;



1 ret=re.findall('abc*?','abcccccc')
2 print(ret)#['ab']



 

  • 元字符之字符集[]:
1 # --------------------------------------------字符集[]
 2 ret = re.findall('a[bc]d', 'acd')   #或的关系[b,c]表示b或c
 3 print(ret)  # ['acd']
 4 
 5 ret = re.findall('[a-z]', 'acd')
 6 print(ret)  # ['a', 'c', 'd']
 7 
 8 #取消元字符的特殊功能
 9 ret = re.findall('[.*+]', 'a.cd+')  #这里的.*+只表示自身意义
10 print(ret)  # ['.', '+']
11 
12 # 在字符集里仍有功能的符号: - ^ \
13 ret = re.findall('[1-9]', '45dha3')     #'-'代表范围
14 print(ret)  # ['4', '5', '3']
15 
16 ret = re.findall('[^a,b]', '45bdha3')    #'^'代表取反即除了a和b以外的
17 #等同于:ret = re.findall('[^ab]', '45bdha3')
18 print(ret)  # ['4', '5', 'd', 'h', '3']
19 
20 
21 # 反斜杠后边跟元字符去除特殊功能,比如\.
22 # 反斜杠后边跟普通字符实现特殊功能,比如\d,相当于类 [0-9]
23 ret = re.findall('[\d]', '45bdha3')
24 print(ret)  # ['4', '5', '3']



反斜杠后边跟元字符去除特殊功能,比如\.

反斜杠后边跟普通字符实现特殊功能,比如\d

\d  匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s  匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b  匹配一个特殊字符边界,比如空格 ,&,#,$等



1 ret=re.findall('I\b','I am LIST')
2 print(ret)#[]   
3 ret=re.findall(r'I\b','I am LI$T')
4 print(ret)#['I','I']



 

 现在我们聊一聊\,先看下面两个匹配:



1 #-----------------------------eg1:
 2 import re
 3 ret=re.findall('c\l','abc\le')
 4 print(ret)#[]   没有匹配
 5 ret=re.findall('c\\l','abc\le')
 6 print(ret)#[]   没有匹配
 7 ret=re.findall('c\\\\l','abc\le')    #在python解释器里先将‘\\\\’转义成‘\\’;再在re模块里将'\\'转义成‘\’ ,即就匹配到了‘c\l’
 8 print(ret)#['c\\l']   匹配到了
 9 ret=re.findall(r'c\\l','abc\le')     #r表示告诉python解释器里面的字符串就是原生字符串,在python接收器中无需转义
10 print(ret)#['c\\l']    匹配到了
11  
12 #-----------------------------eg2:
13 #之所以选择\b是因为\b在ASCII表中是有意义的
14 m = re.findall('\bblow', 'blow')
15 print(m)  #[]     没有匹配
16 m = re.findall(r'\bblow', 'blow')
17 print(m)  #['blow']   匹配到了



 

python模块也是对象吗 python中模块的意义_python模块也是对象吗_08

  

  • 元字符之分组()
1 print(re.search('(as)+','sdjkfasas').group())   #asas    '+' 匹配前面分组[1,+oo]次
2 ret = re.findall('www.(\w+).com','www.baidu.com')  #['baidu']  只会打印出组中的内容
3  ret = re.findall('www.(?:\w+).com','www.baidu.com')   #['www.baidu.com'] 取消组的权限



 

 



1 ret=re.search('(?P<id>\d{2})','23/com')  #?P<id> 为分组取名字为id
2 print(ret.group())#23
3 print(ret.group('id'))#23  #通过分组名取匹配到的值



 

  • 元字符之或 |
ret
=
re.search(
'(?P<id>\d{2})/(?P<name>\w{3})'
,
'23/com'
)



 print (ret.group()) #23/com     



 print (ret.group( 'id' )) #23



 

  • re模块下的常用方法
1 import re
 2 
 3 # 1
 4 re.findall('a', 'alvin yuan')  # ['a', 'a']即返回所有满足匹配条件的结果,放在列表里
 5 # 2
 6 re.search('a', 'alvin yuan').group()  # 'a' 即返回匹配到的第一个对象,对象可以调用group()返回结果;如果字符串没有匹配,则返回None。
 7 
 8 # 3
 9 re.match('a', 'abca').group()  # 'a' 同search,不过只在字符串开始处进行匹配
10 
11 # 4 分割
12 ret = re.split('b', 'abcd')
13 print(ret)  # ['a', 'cd']
14 
15 ret = re.split('[ab]', 'abcd')  # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
16 print(ret)  # ['', '', 'cd']
17 
18 ret = re.split('[js]', 'sdjksal')  #['', 'd', 'k', 'al']
19 
20 # 5 替换
21 ret = re.sub('\d', 'abc', 'alvin5yuan6', 1)
22 print(ret)  # alvinabcyuan6
23 ret = re.subn('\d', 'abc', 'alvin5yuan6')  #没有指定第三个参数,全部替换
24 print(ret)  # ('alvinabcyuanabc', 2)
25 
26 # 6  compile可以把正则表达式编译成一个正则表达式对象,可以把经常使用的正则表达式编译成正则表达式对象,这样可以提高一定的效率。
27 obj = re.compile('\d{3}')  #实现一种规则可以匹配多次
28 ret = obj.search('abc123eeee')
29 print(ret.group())  # 123
30 
31 #7
32 ret = re.finditer('\d','ds3sy4784a')
33 print(res)  #<callable_iterator object at 0x00000233DBFA5208>  返回的结果是迭代器对象
34 print(next(ret).group())  #3



 

json模块 和 pickle模块(序列化的方法)

引入:无法将字典直接写入文件,需要通过eval()方法。不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。



1 # 字典无法直接写入文件
 2 #dic = {'1':'111'}
 3 #f = open('test','w')
 4 #f.write(dic)  #报错 TypeError: write() argument must be str, not dict
 5 
 6 #需要将字典转化成字符串才能写入文件
 7 dic = {'1':'111'}
 8 str1 = str(dic)
 9 f = open('test','w')
10 f.write(str1)    #{'1': '111'} 成功写入文件
11 
12 #读取文件内容
13 # f = open('test','r')
14 # data = f.read()
15 # print(data['1'])   #在文件中保存的是字符串而不是字典,所以这种方式取值将会报错
16 
17 #通过eval转换成字典类型再取值
18 f = open('test','r')
19 data = f.read()
20 print(eval(data)['1'])  #111



 

 

序列化:

我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。

序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。

反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。

 

json:(只能json才能做到不同语言之间的转换)

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

python模块也是对象吗 python中模块的意义_json_09

序列化:dumps 



1 import json
2 dic={'name':'lriwu','age':'18'}
3 data=json.dumps(dic)
4 f=open('json_test','w')   
5 f.write(data)
6 f.close()
7 
8 #文件中保存的内容:
9 #{"name": "lriwu", "age": "18"}   即以json对应的字典格式进行存储(再json中对应的字典类型是{})



 反序列化:loads



1 import json
2 f=open('json_test','r')
3 # data=f.read()
4 # data['name']   #dumps序列化的无法直接通过read()方法读,需要通过loads方法进行反序列化
5 data=f.read()
6 data=json.loads(data)
7 print(data['name'])   #lriwu



 

 json可以对普通的数据类型转化成json的字符串;但是不能将高级的对象(函数或类)转化成json的字符串。



1 import json
2 
3 def foo():
4     print('ok')
5 
6 data=json.dumps(foo)  #TypeError: <function foo at 0x00000225799AC620> is not JSON serializable 函数不是json的序列化类型



 

 json可以对普通的数据类型转化成json的字符串;但是不能将高级的对象(函数或类)转化成json的字符串,如果需要将这些高级的对象转化成jison的字符串,可以使用pickle。

 

pickle:

序列化:dumps 



1 import pickle
 2 
 3 def foo():
 4     print('ok')
 5 
 6 data=pickle.dumps(foo)
 7 f=open('pickle_test','wb')  #pickle必须是bytes数据类型,字符串类型无法写入;'wb':表示把写入文件的内容转化为bytes之后再写入文件;‘w’:写入的是str的数据类型
 8 f.write(data)  
 9 f.close()
10 
11 #f=open('pickle_test','w') 将会报错TypeError: write() argument must be str, not bytes



 反序列化:loads



1 import pickle
2 def foo():
3     print('ok')
4 f=open('pickle_test','rb')
5 data=f.read()
6 data=pickle.loads(data)
7 data()  #调用data就相当于执行了foo()函数,前提是当前脚本也需要定义foo()函数即load和dumps两个文件都必须要有foo()函数



 

 

dump和load方法:



1 import json
2 dic = {'name':'lriwu','age':'18'}
3 f = open('JSON_test','w')
4 # data = json.dumps(dic)
5 # f.write(data)
6 json.dump(dic,f) #这句话等同于data = json.dumps(dic)和f.write(data)这两句即f.write(data)省略了
7 f.close()



 



1 import json
2 f=open('JSON_test','r')
3 # data=f.read()
4 # data=json.loads(data)
5 data = json.load(f)  #少了f.read()
6 print(data['name'])   #lriwu



 

 

shelve模块

shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型。

存数据:



1 import shelve
2 f = shelve.open('shelve.txt')  #得到一个文件句柄
3  
4 f['stu1_info']={'name':'alex','age':'18'}   #后续还能继续添加其它字典,非常灵活
5 #print(f['stu1_info'])    {'name':'alex','age':'18'}  
7 #print(f['stu1_info']['age'])  #18
8 #print(f.get('stu1_info')['age']) #18 取字典中的内容(本地取)



 

取数据:(在另外一个文件中取上述存的数据)



import shelve
 
f = shelve.open('shelve.txt')

data = f.get('stu1_info')['age']
print(data)   #18



 

get方法



1 d = {'name':'lriwu','age':'18'}
 2 #取键值,方法一:
 3 print(d['name'])  #lriwu
 4 #print(d.['sex'])  #无该键将会报错
 5 
 6 
 7 #取键值,方法二:
 8 print(d.get('name')) #lriwu
 9 print(d.get('sex')) #None 无该键将会返回None
10 print(d.get('sex','male'))  #male 该键将会返回自定义的值



 

xml模块

xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。

xml的格式如下,就是通过<>节点来区别数据结构的:



1 <?xml version="1.0"?>
 2 <data>
 3     <country name="Liechtenstein">
 4         <rank updated="yes">2</rank>
 5         <year>2008</year>
 6         <gdppc>141100</gdppc>
 7         <neighbor name="Austria" direction="E"/>
 8         <neighbor name="Switzerland" direction="W"/>
 9     </country>
10     <country name="Singapore">
11         <rank updated="yes">5</rank>
12         <year>2011</year>
13         <gdppc>59900</gdppc>
14         <neighbor name="Malaysia" direction="N"/>
15     </country>
16     <country name="Panama">
17         <rank updated="yes">69</rank>
18         <year>2011</year>
19         <gdppc>13600</gdppc>
20         <neighbor name="Costa Rica" direction="W"/>
21         <neighbor name="Colombia" direction="E"/>
22     </country>
23 </data>



xml协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml:



1 import xml.etree.ElementTree as ET
 2 
 3 tree = ET.parse("xmltest.xml")    #xmltest.xml 文件名,得到一个xml对象
 4 root = tree.getroot()
 5 print(root.tag)     #data 即得到最外层的标签名字
 6 
 7 # 遍历xml文档
 8 for child in root:
 9     print(child.tag, child.attrib)  #得到 country {'name':'Liechtenstein'}  country {'name':'Singapore'}   country {'name':'Panama'}
10     for i in child:
11         print(i.tag, i.text)
12 
13 # 只遍历year 节点
14 for node in root.iter('year'):
15     print(node.tag, node.text)
16 # ---------------------------------------
17 
18 import xml.etree.ElementTree as ET
19 
20 tree = ET.parse("xmltest.xml")
21 root = tree.getroot()
22 
23 # 修改
24 for node in root.iter('year'):
25     new_year = int(node.text) + 1  #年份加1
26     node.text = str(new_year)
27     node.set("updated", "yes")    #新加一个属性   <year> upadta='yes'>2009</year>  <year> upadta='yes'>2012</year>  <year> upadta='yes'>2012</year>
28 
29 
30 tree.write("xmltest.xml")
31 
32 # 删除node
33 for country in root.findall('country'):
34     rank = int(country.find('rank').text)
35     if rank > 50:
36         root.remove(country)
37 
38 tree.write('output.xml')



自己创建xml文档:



1 import xml.etree.ElementTree as ET
 2  
 3  
 4 new_xml = ET.Element("namelist")
 5 name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
 6 age = ET.SubElement(name,"age",attrib={"checked":"no"})
 7 sex = ET.SubElement(name,"sex")
 8 sex.text = '33'
 9 name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
10 age = ET.SubElement(name2,"age")
11 age.text = '19'
12  
13 et = ET.ElementTree(new_xml) #生成文档对象
14 et.write("test.xml", encoding="utf-8",xml_declaration=True)
15  
16 ET.dump(new_xml) #打印生成的格式



 

python模块也是对象吗 python中模块的意义_python_10

 

subprocess模块




python模块也是对象吗 python中模块的意义_字符串_06

python模块也是对象吗 python中模块的意义_shell_07

import subprocess
################subprocess 案例1
# a= subprocess.Popen('dir', shell=True)  #实例化一个对象,并将命令执行结果输出在屏幕;这里的subprocess自己开了一个子进程,执行结果由该子进程输出至屏幕,这个子进程和主进程无关;subprocess.Popen('dir', shell=True)和print(a)谁先输出取决于谁的执行速度快
# print(a)

# 输出
# <subprocess.Popen object at 0x000001C1386E2978>
# 2018/03/08  15:34    <DIR>          .
# 2018/03/08  15:34    <DIR>          ..
# 2018/03/08  11:24               357 client.py
# 2018/03/08  15:33             1,014 server.py
# 2018/03/08  15:34               370 subpro.py
# 2018/03/08  15:31    <DIR>          __pycache__

################subprocess 案例2
# a=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE) #实例化一个对象,命令执行结果不会在屏幕输出,该执行结果保存在subprocess的子进程中;stdout=subprocess.PIPE就是将执行结果通过管道从子进程保存到主进程上,以便通过方法可以获取到执行结果
# print(a)  #获取执行的结果

#输出:<subprocess.Popen object at 0x000001C77CCA2978>
#这时候执行结果就不会在屏幕上输出了

################subprocess 案例2 通过方法调用执行结果
# a=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
# #print(a.stdout.read())      #输出的是bytes类型 b' \xc7\xfd\xb6\xaf\xc6\xf7 F \xd6\xd0\xb5\xc4\xbe\xed\xca\xc7 studying\r\n \xbe\xed\xb5\xc4\xd0\xf2\xc1\xd0\xba\xc5\xca\xc7 0006-6FF7\r\n\r\n F:\\code\\day26 \xb5\xc4\xc4\xbf\xc2\xbc\r\n\r\n2018/03/08  15:56    <DIR>          .\r\n2018/03/08  15:56    <DIR>          ..\r\n2018/03/08  11:24               357 client.py\r\n2018/03/08  15:33             1,014 server.py\r\n2018/03/08  15:56             1,454 subpro.py\r\n2018/03/08  15:31    <DIR>          __pycache__\r\n               3 \xb8\xf6\xce\xc4\xbc\xfe          2,825 \xd7\xd6\xbd\xda\r\n               3 \xb8\xf6\xc4\xbf\xc2\xbc 81,451,225,088 \xbf\xc9\xd3\xc3\xd7\xd6\xbd\xda\r\n'
# print(str(a.stdout.read(),'gbk'))

# 输出:
# 2018/03/08  16:01    <DIR>          .
# 2018/03/08  16:01    <DIR>          ..
# 2018/03/08  11:24               357 client.py
# 2018/03/08  15:33             1,014 server.py
# 2018/03/08  16:01             2,132 subpro.py
# 2018/03/08  15:31    <DIR>          __pycache__
#                3 个文件          3,503 字节
#                3 个目录 81,451,225,088 可用字节