模块
 collections模块
 1、namedtuple:生成可以使用名字来访问元素内容的tuple
 from collections import namedtuple
 namedtuple('名称', [属性list]):
 from collections import namedtuple
 Point = namedtuple('Point', ['x', 'y'])
 p = Point(1, 2)

 2、deque:双端队列,可以快速地从另外一侧追加和推出对象
 from collections import deque
 q = deque(['a','b'])
 q.append('x')      追加
 q.appendleft('c')   左侧追加
 print(q)
 q.popleft()       左侧删除
 print(q)

 3、Counter:计数器,主要用来计数
from collections import Counter

 c = Counter('abcdeabcdabcaba')
 print(c)
 输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})

 4、OrderedDict:有序字典
 python2 dict是无序的。
 from collections import OrderedDict
 d = dict([('a', 1), ('b', 2), ('c', 3)])
 # d # dict的Key是无序的 {'a': 1, 'c': 3, 'b': 2}
 od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
 # od # OrderedDict的Key是有序的
 OrderedDict([('a', 1), ('b', 2), ('c', 3)])

 OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:
 od = OrderedDict()
 od['z'] = 1
 od['y'] = 2
 od['x'] = 3
 print(od.keys()) # 按照插入的Key的顺序返回

 5、defaultdice:带有默认值的字典
 有如下值集合 [11,22,33,44,55,66,77,88,99,90...],
 将所有大于 66 的值保存至字典的第一个key中,
 将小于 66 的值保存至第二个key的值中。
 即: {'k1': 大于66 , 'k2': 小于66}
 from collections import defaultdict
 values = [11, 22, 33,44,55,66,77,88,99,90]
 my_dict = defaultdict(list)
 for value in  values:
     if value>66:
         my_dict['k1'].append(value)
     else:
         my_dict['k2'].append(value)

 使用dict时,如果引用的Key不存在,就会抛出KeyError。
 如果希望key不存在时,返回一个默认值,就可以用defaultdict:
 from collections import defaultdict
 dd = defaultdict(lambda: 'N/A')
 dd['key1'] = 'abc'
 dd['key1'] # key1存在
 'abc'
 dd['key2'] # key2不存在,返回默认值
 'N/A'


 time 时间模块
 常用方式
 1、time.sleep(secs)   推迟运行
 2、time.time()        获取当前时间时间戳

 时间日期格式化符号
 %Y 年
 %m 月
 %d 日

 %H 时
 %M 分
 %S 秒

 时间格式
 time.time()     时间戳
 time.strftime(时间格式字符串)    时间字符串
 时间元组:
 time.localtime()
 time.struct_time()

 时间转化:
 时间戳时间--->结构化时间--->字符串时间
 import time
 a = time.time()
 print(a)
 b = time.localtime(a)     # 或者gmtime
 print(b)
 c = time.strftime('%Y-%m-%d')
 print(c)

 字符串时间--->结构化时间--->时间戳时间
 import time
 i = '2018-06-09'
 d = time.strftime(i)
 print(d)
 e = time.strptime(d,"%Y-%m-%d")
 print(e)
 f = time.mktime(e)
 print(f)


 random模块
 随机小数
 random.randon()  # 大于0且小于1之间的小数
 random.uniform(int1,int2)  # 大于int1小于int2的小数

 随机整数
 random.randint(int1,int2) # 大于等于int1且小于等于int2之间的整数
 random.randrande(int1,int2,int3) # 大于等于int1且小于int2之间的int3步长

 随机选择一个返回
 random.chhoice(list)   随机选择列表中的一个返回
 随机选择多个返回
 random.sample(list,int1)  随机选择列表中的int1个数返回

 打乱列表顺序
 random.shuffle(list)


 os模块
 os模块是与操作系统交互的一个接口

工作路径相关:
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
os.curdir  返回当前目录: ('.')
os.pardir  获取当前目录的父目录字符串名:('..')

文件文件夹相关:
os.makedirs('dirname1/dirname2')    可生成多层递归目录
os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  删除一个文件
os.rename("oldname","newname")  重命名文件/目录
os.stat('path/filename')  获取文件/目录信息

操作系统差异相关:
os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep    输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'

执行操作系统命令相关:
os.system("bash command")  运行shell命令,直接显示
os.popen("bash command).read()  运行shell命令,获取执行结果

os.environ  获取系统环境变量


os.path
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.path.getsize(path) 返回path的大小
'''


 sys模块
 sys模块是与python解释器交互的一个接口
 sys.argv           命令行参数List,第一个元素是程序本身路径
 sys.exit(n)        退出程序,正常退出时exit(0),错误退出sys.exit(1)
 sys.version        获取Python解释程序的版本信息
 sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
 sys.platform       返回操作系统平台名称

 异常处理和status:
 import sys
 try:
     sys.exit(1)
 except SystemExit as e:
     print(e)


 序列化模块
 将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化。

 序列化的目的
 1、以某种存储形式使自定义对象持久化;
 2、将对象从一个地方传递到另一个地方。
 3、使程序更具维护性。

 json模块
 json  用于字符串和python数据类型间进行转换
 Json模块提供了四个功能:
 dumps    序列化   json.dumps()
 loads    反序列化    json.loads()

 dump   json.dump(str,文件句柄)
 load   json.load(文件句柄)


 pickle模块
 pickle  用于python特有的类型和python的数据类型间进行转换  只有python能识别
 pickle模块提供了四个功能:
 dumps (序列化)
 loads(反序列化)
 dump(序列化,存)
 load(不仅可以序列化字典,列表...可以把python中任意的数据类型序列化)


 shelve模块
 了解即可


 re模块
 弄懂re模块之前先弄懂正则表达式
 正则表达式是对字符串的一种过滤逻辑。

 import re

 ret = re.findall('a', 'eva egon yuan')  # 返回所有满足匹配条件的结果,放在列表里
 print(ret) #结果 : ['a', 'a']

 ret = re.search('a', 'eva egon yuan').group()
 print(ret) #结果 : 'a'
 # 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。

 ret = re.match('a', 'abc').group()  # 同search,不过尽在字符串开始处进行匹配
 print(ret)
 #结果 : 'a'

 ret = re.split('[ab]', 'abcd')  # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
 print(ret)  # ['', '', 'cd']

 ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1)#将数字替换成'H',参数1表示只替换1个
 print(ret) #evaHegon4yuan4

 ret = re.subn('\d', 'H', 'eva3egon4yuan4')#将数字替换成'H',返回元组(替换的结果,替换了多少次)
 print(ret)

 obj = re.compile('\d{3}')  #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
 ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串
 print(ret.group())  #结果 : 123

 import re
 ret = re.finditer('\d', 'ds3sy4784a')   #finditer返回一个存放匹配结果的迭代器
 print(ret)  # <callable_iterator object at 0x10195f940>
 print(next(ret).group())  #查看第一个结果
 print(next(ret).group())  #查看第二个结果
 print([i.group() for i in ret])  #查看剩余的左右结果


 1、findall的优先级查询:
 import re

 ret = re.findall('www.(baidu|ngz).kim', 'www.ngz.kim')
 print(ret)  # ['ngz']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可

 ret = re.findall('www.(?:baidu|ngz).kim', 'www.ngz.kim')
 print(ret)  # ['www.ngz.kim']


 2、split的优先级查询
 ret=re.split("\d+","eva3egon4yuan")
 print(ret) #结果 : ['eva', 'egon', 'yuan']

 ret=re.split("(\d+)","eva3egon4yuan")
 print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']

 #在匹配部分加上()之后所切出的结果是不同的,
 #没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项,
 #这个在某些需要保留匹配部分的使用过程是非常重要的。


 hashlib
 本质上是一种摘要,因为不能解密所以只能勉强叫做照耀算法,不能算是加密算法
 import hashlib
 md5 = hashlib.md5(可以加盐)
 md5.update('how to use md5 in python hashlib?'.encode('utf-8'))    # upadte也可以分多次调用  结果一样  用于数据很大的情况下进行摘要处理
 print(md5.hexdigest())
 计算结果如下:
 d26a53750bc40b38b65a520292f69306


 fonfigparser模块
 该模块适用于配置文件的格式与windows ini文件类似,
 可以包含一个或多个节(section),每个节可以有多个参数(键=值)。

 如要配置如下格式的文件格式
 [DEFAULT]
 ServerAliveInterval = 45
 Compression = yes
 CompressionLevel = 9
 ForwardX11 = yes

 [bitbucket.org]
 User = hg

 [topsecret.server.com]
 Port = 50022
 ForwardX11 = no
 利用fonfigparser模块进行生成的用法:
 import configparser

 config = configparser.ConfigParser()

 config["DEFAULT"] = {'ServerAliveInterval': '45',
                       'Compression': 'yes',
                      'CompressionLevel': '9',
                      'ForwardX11':'yes'
                      }

 config['bitbucket.org'] = {'User':'hg'}

 config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}

 with open('example.ini', 'w') as configfile:

    config.write(configfile)


 查找的用法:
 import configparser

 config = configparser.ConfigParser()

 #---------------------------查找文件内容,基于字典的形式

 print(config.sections())        #  []

 config.read('example.ini')

 print(config.sections())        #   ['bitbucket.org', 'topsecret.server.com']

 print('bytebong.com' in config) # False
 print('bitbucket.org' in config) # True


 print(config['bitbucket.org']["user"])  # hg

 print(config['DEFAULT']['Compression']) #yes

 print(config['topsecret.server.com']['ForwardX11'])  #no


 print(config['bitbucket.org'])          #<Section: bitbucket.org>

 for key in config['bitbucket.org']:     # 注意,有default会默认default的键
     print(key)

 print(config.options('bitbucket.org'))  # 同for循环,找到'bitbucket.org'下所有键

 print(config.items('bitbucket.org'))    #找到'bitbucket.org'下所有键值对

 print(config.get('bitbucket.org','compression')) # yes       get方法Section下的key对应的value


 增删改的操作:
 import configparser

 config = configparser.ConfigParser()

 config.read('example.ini')

 config.add_section('yuan')



 config.remove_section('bitbucket.org')
 config.remove_option('topsecret.server.com',"forwardx11")


 config.set('topsecret.server.com','k1','11111')
 config.set('yuan','k2','22222')

 config.write(open('new2.ini', "w"))


 logging模块
 import logging
 logging.debug('debug message')
 logging.info('info message')
 logging.warning('warning message')
 logging.error('error message')
 logging.critical('critical message')

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


 灵活配置日志级别,日志格式,输出位置:
 import logging

 logging.basicConfig(level=logging.DEBUG,
                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                     datefmt='%a, %d %b %Y %H:%M:%S',
                     filename='/tmp/test.log',
                     filemode='w')

 logging.debug('debug message')
 logging.info('info message')
 logging.warning('warning message')
 logging.error('error message')
 logging.critical('critical message')

 logger对象配置:
 import logging

 logger = logging.getLogger()
 # 创建一个handler,用于写入日志文件
 fh = logging.FileHandler('test.log',encoding='utf-8')

 # 再创建一个handler,用于输出到控制台
 ch = logging.StreamHandler()
 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 fh.setLevel(logging.DEBUG)

 fh.setFormatter(formatter)
 ch.setFormatter(formatter)
 logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
 logger.addHandler(ch)

 logger.debug('logger debug message')
 logger.info('logger info message')
 logger.warning('logger warning message')
 logger.error('logger error message')
 logger.critical('logger critical message')

 logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,
 Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。
 另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过

 fh.setLevel(logging.Debug)单对文件流设置某个级别。


 模块和包
 sys.modules
 我们可以从sys.modules中找到当前已经加载的模块,
 sys.modules是一个字典,内部包含模块名与模块对象的映射,
 该字典决定了导入模块时是否需要重新导入。

 模块起别名
 import my_module as sm
 print(sm.money)

 在一行导入多个模块
 import sys,os,re


 from ... import...
 也支持as
 from my_module import read1 as read

 也支持导入多行
 from my_module import (read1,
                read2,
                money)


 rom my_module import *
 把my_module中所有的不是以下划线(_)开头的名字都导入到当前位置,
 大部分情况下我们的python程序不应该使用这种导入方式,
 因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。
 而且可读性极其的差,在交互式环境中导入时没有问题。


 把模块当做脚本执行
 我们可以通过模块的全局变量__name__来查看模块名:
 当做脚本运行:
 __name__ 等于'__main__'

 当做模块导入:
 __name__= 模块名

 作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
 if __name__ == '__main__':


 模块搜索路径
 模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
 需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。



 包
 1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法

 2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)

 3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

 强调:

   1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

   2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块



 绝对导入和相对导入
 我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:
 绝对导入:以glance作为起始
 相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)

 特别需要注意的是:可以用import导入内置或者第三方模块(已经在sys.path中),
 但是要绝对避免使用import来导入自定义包的子模块(没有在sys.path中),
 应该使用from... import ...的绝对或者相对导入,且包的相对导入只能用from的形式。

 软件开发规范目录结构
 soft
     bing      # 存放执行脚本
         pass
     conf      # 存放配置文件
         pass
     core      # 存放核心逻辑
         pass
     db        # 存放数据库文件
         pass
     lib       # 存放自定义的模块与包
         pass
     log       # 存放日志
         pass