模块与包&常用模块

一、模块的使用

模块定义:一系列功能的集合体

分为三大类:1.自定义模块

      2.内置模块(比如 time,os,sys)

      3.第三方模块

模块的表现形式

  1.使用python编写的py文件

  2.已被编译为共享库或DLL的C或C++扩展

  3.把一系列模块组织到一起的文件夹(ps:文件夹下有一个__init__.py文件,该文件夹称为包)

  4.使用C编写并链接到python解释器的内置模块

为什么要用模块:

  1.可以拿来内置、第三方的模块,然后直接使用,这种拿来就用的方式,会极大的提升开发效率

  2.将程序中共用的一些功能组织到一个文件中,然后程序各部分组件可以重用该文件中的功能。

    优点是 减少代码冗余,增强程序的组织结构性与可维护性

怎么用模块:

  一个py文件就是一个模块,如果文件名为modules.py,模块名则为modules

  ps:模块的使用必须搞清楚谁是执行文件,谁是被导入的模块

1、模块的使用之import

#:coding:utf-8
#modules.py
print('from the modules.py')

money=1000

def read1():
    print('modules模块.read1',money)

def read2():
    print('modules模块.read2')
    read1()

def change():
    global money
    money=0
modules.py
import modules 

money=111111111111
print(modules.money)
print(modules.read1)
print(modules.read2)
print(modules.change)
modules.money=2222
print(money)###结果为money=111111111111

modules.read1()#modules模块.read1 2222   #这个更改成功modules.money=2222

def read1():#此处定义read1
    print('run.py中的read1')

modules.read1()#执行结果仍为modules模块.read1 2222

money=20000000
modules.change()#此处执行了modules中change函数
print(money)###此处为上述money=20000000
print(modules.money)##结果为0


import modules as spam ##可以as 起个别名
print(spam.money)  #依旧执行成功  结果为0
run.py

执行文件:run.py      被导入模块是:modules.py

首次导入模块会发生三件事: 

  1、创建一个模块modules.py的名称空间
  2、执行模块对应的文件modules.py,将产生的名字丢到模块的名称空间中
  3、在当前执行文件的名称空间中拿到一个名字modules,该名字就是指向模块modules.py的名称空间的
  import modules# modules=modules.py名称空间的内存地址

ps

  在当前执行文件中引用模块中的名字语法为:modules.名字,必须加上modules.作为前缀
  modules.名字相当于指名道姓地跟某一个名称空间要名字,根本不会与当前执行文件的名字冲突

2、模块的使用之  from   import

#modules.py
# print('from the modules.py')

__all__=['money','read1']

money=1000

def read1():
    print('spam模块.read1',money)

def read2():
    print('spam模块.read2')
    read1()

def change():
    global money
    money=0
spam.py
from spam import money,read1,read2,change
#
def read1():
    print('run.py.read1')

read1()      #  run.py.read1
read2()      #  spam模块.read2  ------------>   spam模块.read1 1000


from spam import money as my
print(my)   #1000

# ===========================================
from spam import * # * 会检索被导入模块中的__all__指定的名字,如果没有该变量那默认导入所有
print(money)  #1000
print(read1)  # <function read1 at 0x0000000001EB1C80>
# print(read2) #会报错
# print(change) #会报错
run.py

执行文件:run.py      被导入模块: spam.py

首次导入模块会发生三件事
  1、创建一个模块spam.py的名称空间
  2、执行模块对应的文件spam.py,将产生的名字丢到模块的名称空间中
  3、在当前执行文件的名称空间中拿到一个名字money,该名字就是指向模块spam.py的名称空间的那个money
  from spam import money,read1,read2,change

两种导入方式的对比
相同点:函数的作用域关系在定义阶段就规定死了,与调用位置无关

from import
优点:可以不用加前缀而直接引用名字,更简洁
缺点:容易与当前执行文件中的名字冲突

import
优点:指名道姓跟某一个名称空间要名字,肯定不会与当前名称空间中的名字冲突
缺点:必须加上前缀

3、循环导入的问题

# print('正在导入m1')
#
# x='m1.py'
#
# from m2 import y
#

print('正在导入m1')

def f1():
    from m2 import y,f2
    print(y)
    f2()

x='m1.py'
m1.py
# print('正在导入m2')
#
# y='m2'
#
# from m1.py import x


print('正在导入m2')

def f2():
    from m1 import x
    print(x)

y='m2.py'
m2.py
###   run.py
# 1、创建m1.py的名称空间
# 2、执行m1.py的代码,将产生的名字丢到m1.py的名称空间中
# 3、在当前执行文件的名称空间中拿到一个名字m1
import m1

m1.f1()

4、模块的搜索路径

模块搜索路径优先级:

  内存  --------> 内置的模块 --------> sys.path(环境变量)

#模块的查找顺序
1、在第一次导入某个模块时(比如spam),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用
    ps:python解释器在启动时会自动加载一些模块到内存中,可以使用sys.modules查看
2、如果没有,解释器则会查找同名的内建模块
3、如果还没有找到就从sys.path给出的目录列表中依次寻找spam.py文件。


#sys.path的初始化的值来自于:
The directory containing the input script (or the current directory when no file is specified).
PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
The installation-dependent default.

#需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。虽然每次都说,但是仍然会有人不停的犯错。 

#在初始化后,python程序可以修改sys.path,路径放到前面的优先于标准库被加载。
1 >>> import sys
2 >>> sys.path.append('/a/b/c/d')
3 >>> sys.path.insert(0,'/x/y/z') #排在前的目录,优先被搜索
注意:搜索时按照sys.path中从左到右的顺序查找,位于前的优先被查找,sys.path中还可能包含.zip归档文件和.egg文件,python会把.zip归档文件当成一个目录去处理,

#首先制作归档文件:zip module.zip foo.py bar.py 
import sys
sys.path.append('module.zip')
import foo,bar

#也可以使用zip中目录结构的具体位置
sys.path.append('module.zip/lib/python')


#windows下的路径不加r开头,会语法错误
sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\a')
 

#至于.egg文件是由setuptools创建的包,这是按照第三方python库和扩展时使用的一种常见格式,.egg文件实际上只是添加了额外元数据(如版本号,依赖项等)的.zip文件。

#需要强调的一点是:只能从.zip文件中导入.py,.pyc等文件。使用C编写的共享库和扩展块无法直接从.zip文件中加载(此时setuptools等打包系统有时能提供一种规避方法),且从.zip中加载文件不会创建.pyc或者.pyo文件,因此一定要事先创建他们,来避免加载模块是性能下降。
详细的介绍

5、区分python文件的两种用途

一个python文件有两种用途:(模块与脚本)
  1、可以执行运行:__name__ == '__main__'
  2、可以被当做模块导入:__name__ == '模块名'

if __name__ == '__main__':

二、包的使用

1、什么是包

官网解释

Packages are a way of structuring Python’s module namespace by using “dotted module names”

包是一种通过使用‘.模块名’来组织python模块名称空间的方式

具体的:包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来

需要强调的是:   

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

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

2、为什么要用包

包的本质就是一个文件夹,  那么文件夹唯一的功能就是将文件组织起来 随着功能越写越多  ,我们无法将所以功能都放到一个文件中, 于是我们使用模块去组织功能, 而随着模块越来越多, 我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性。

ps:注意事项

#1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。

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

#3、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间

 

|---示例
|     ||---dir1 #文件夹
|     |     |-----dir2 #文件夹
|     |            |---p1 #包文件夹
|     |               |||-------p2 #包文件夹
|     |               |||       ||----- __init__.py
|     |               |||       |------m3.py
|     |               |||
|     |               |||--- __init__.py
|     |               ||----m1.py     
|     |               |-----m2.py   
|     |
|     |------run.py  #执行文件
#   run.py

from dir1.dir2 import p1
p1.f1()
p1.f2()
p1.f3()

#======================================
#dir1文件夹 (dir2文件夹)
#
#dir2文件夹(p1包文件夹)
#======================================
                          #p1下的文件内容
#__init.py

from .m1 import f1
from .m2 import f2
from .p2.m3 import f3
#------------------------------------------
#m1.py

def f1():
    print('m1.f1')
#-------------------------------------------
#m2.py

def f2():
    print('m2.f2')
#-------------------------------------------
#p1包文件夹(p2包文件夹)
#=======================================
                         #p2下的文件内容
#__init__.py

#
#--------------------------------------------
#m3.py

def f3():
    print('m3.f3')
文件内容
#import p1
#1 创建p1的名称空间
#2 执行p1下的__init__.py文件的代码,将执行过程中产生的名字都丢到名称空间中
#3 在当前执行文件中拿到一个名字p1,p1指向__init__.py的名称空间
#包内模块的:绝对导入与相对导入
#    绝对导入:每次导入都是以最顶级包为起始开始查找的
#    相对导入:相对于当前所在的文件,.代表当前所在的文件,..代表上一级,...
#        强调:
#            相对导入只能在被导入的模块中使用
#           在执行文件里不能用.或者..的导入方式

#注意:
# 但凡在导入时带点的,点的左边必须是一个包

三、软件开发的目录规范

  

1、bin 文件夹  :一般放程序启动文件(start.py)

2、conf 文件夹:一些配置信息(例如路径等)

3、core 文件夹:程序的核心文件 与用户挂钩的

4、db 文件夹   :数据文件所在地

5、lib 文件夹   :公共模块文件(例如认证文件)

6、log 文件夹  :日志文件所在地 

7、Readme 文件   :程序的帮助文档

四、logging模块(日志)

一、日志的级别

CRITICAL = 50 #FATAL = CRITICAL
ERROR = 40
WARNING = 30 #WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0 #不设置

二、默认级别为warning ,默认打印到终端

import logging

logging.debug('调试debug')
logging.info('消息info')
logging.warning('警告warn')
logging.error('错误error')
logging.critical('严重critical')

'''
WARNING:root:警告warn
ERROR:root:错误error
CRITICAL:root:严重critical
'''

三、为logging 模块指定全局配置

针对所有logger有效,控制打印到文件

可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。

filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。

format:指定handler使用的日志显示格式。
 
datefmt:指定日期时间格式。 

level:设置rootlogger 的日志级别 

stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。


#格式
%(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:用户输出的消息  
logging.basicConfig()
#========使用
import logging
logging.basicConfig(filename='access.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('警告warn')
logging.error('错误error')
logging.critical('严重critical')





#========结果
access.log内容:
2017-07-28 20:32:17 PM - root - DEBUG -test:  调试debug
2017-07-28 20:32:17 PM - root - INFO -test:  消息info
2017-07-28 20:32:17 PM - root - WARNING -test:  警告warn
2017-07-28 20:32:17 PM - root - ERROR -test:  错误error
2017-07-28 20:32:17 PM - root - CRITICAL -test:  严重critical

part2: 可以为logging模块指定模块级的配置,即所有logger的配置
固定套路

四、logging模块的对象

Formatter ,Handler,Logger,Filte

#logger:产生日志的对象

#Filter:过滤日志的对象

#Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端

#Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式
'''
critical=50
error =40
warning =30
info = 20
debug =10
'''


import logging

#1、logger对象:负责产生日志,然后交给Filter过滤,然后交给不同的Handler输出
logger=logging.getLogger(__file__)#日志名

#2、Filter对象:不常用,略

#3、Handler对象:接收logger传来的日志,然后控制输出
h1=logging.FileHandler('t1.log') #打印到文件
h2=logging.FileHandler('t2.log') #打印到文件
h3=logging.StreamHandler() #打印到终端

#4、Formatter对象:日志格式
formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',)

formmater2=logging.Formatter('%(asctime)s :  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',)

formmater3=logging.Formatter('%(name)s %(message)s',)


#5、为Handler对象绑定格式
h1.setFormatter(formmater1)
h2.setFormatter(formmater2)
h3.setFormatter(formmater3)

#6、将Handler添加给logger并设置日志级别
logger.addHandler(h1)
logger.addHandler(h2)
logger.addHandler(h3)
logger.setLevel(10)

#7、测试
logger.debug('debug')
logger.info('info')
logger.warning('warning')
logger.error('error')
logger.critical('critical')
logging模块的固定套路

详细步骤

1、配图

1、logger对象负责产生日志

logger1=logging.getLogger('xx日志')

2、filter过滤(基本用不到)

3、绑定1

handler对象需要与logger对象绑定用来接收logger对象传过来的日志,控制打印到不同的地方(文件、终端)

fh1=logging.FileHandler(filename='a1.log',encoding='utf-8')
fh2=logging.FileHandler(filename='a2.log',encoding='utf-8')

sh=logging.StreamHandler()# 往终端打印的

4、绑定2

formmater对象需要与handler对象绑定用于控制handler对象的日志格式

formmater1=logging.Formatter(
    fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p'
)

#两种不同的日志格式

formmater2=logging.Formatter(
    fmt='%(asctime)s - %(levelname)s :  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p'
)
formmater格式

ps1:设置日志级别(统一设置):logger与handler两层关卡都放行,日志最终才放行

logger1.setLevel(10)  #logger对象设置

fh1.setLevel(10)  #文件1的handler设置级别
fh2.setLevel(20)  #文件2的handler设置级别
sh.setLevel(30)   #打印到终端的handler设置级别

ps2:建立logger对象与handler对象的绑定关系

logger1.addHandler(fh1)
logger1.addHandler(fh2)
logger1.addHandler(sh)

ps3:建立handler对象与formmater对象的绑定关系

fh1.setFormatter(formmater1)
fh2.setFormatter(formmater1)
sh.setFormatter(formmater2)

最终:使用logger1对象产生日志,打印到不同的位置

logger1.debug('蘑菇买彩票中奖30元')
logger1.warning('蘑菇花了1000元买彩票')

五、Logger与Handler的级别

 logger与handler两层关卡都放行,日志最终才放行

注意:logger是第一层关卡  ,然后才到handler

import logging


form=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',)

ch=logging.StreamHandler()

ch.setFormatter(form)
# ch.setLevel(10)
ch.setLevel(20)

l1=logging.getLogger('root')
# l1.setLevel(20)
l1.setLevel(10)
l1.addHandler(ch)

l1.debug('l1 debug')
示例

六、具体模块的使用方法

如果每次使用模块都得按照上述的步骤,那就太繁琐了。

所以logging模块有一个从字典中加载配置的方法

1.应用模板

"""
logging配置
"""

import os
import logging.config

# 定义三种日志输出格式 开始

standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                  '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'

# 定义日志输出格式 结束

logfile_dir = os.path.dirname(os.path.abspath(__file__))  # log文件的目录

logfile_name = 'all2.log'  # log文件名

# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
    os.mkdir(logfile_dir)

# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)

# log配置字典
LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
    },
    'filters': {},
    'handlers': {
        #打印到终端的日志
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'
        },
        #打印到文件的日志,收集info及以上的日志
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
            'formatter': 'standard',
            'filename': logfile_path,  # 日志文件
            'maxBytes': 1024*1024*5,  # 日志大小 5M
            'backupCount': 5,
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
    },
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        '': {
            'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)传递
        },
    },
}


def load_my_logging_cfg():
    logging.config.dictConfig(LOGGING_DIC)  # 导入上面定义的logging配置
    logger = logging.getLogger(__name__)  # 生成一个log实例
    logger.info('It works!')  # 记录该文件的运行状态

if __name__ == '__main__':
    load_my_logging_cfg()

logging配置文件
logging配置模板
"""
MyLogging Test
"""

import time
import logging
import my_logging  # 导入自定义的logging配置

logger = logging.getLogger(__name__)  # 生成logger实例


def demo():
    logger.debug("start range... time:{}".format(time.time()))
    logger.info("中文测试开始。。。")
    for i in range(10):
        logger.debug("i:{}".format(i))
        time.sleep(0.2)
    else:
        logger.debug("over range... time:{}".format(time.time()))
    logger.info("中文测试结束。。。")

if __name__ == "__main__":
    my_logging.load_my_logging_cfg()  # 在你程序文件的入口加载自定义logging配置
    demo()
使用
#1、有了上述方式我们的好处是:所有与logging模块有关的配置都写到字典中就可以了,更加清晰,方便管理


#2、我们需要解决的问题是:
    1、从字典加载配置:logging.config.dictConfig(settings.LOGGING_DIC)

    2、拿到logger对象来产生日志
    logger对象都是配置到字典的loggers 键对应的子字典中的
    按照我们对logging模块的理解,要想获取某个东西都是通过名字,也就是key来获取的
    于是我们要获取不同的logger对象就是
    logger=logging.getLogger('loggers子字典的key名')

    
    但问题是:如果我们想要不同logger名的logger对象都共用一段配置,那么肯定不能在loggers子字典中定义n个key   
 'loggers': {    
        'l1': {
            'handlers': ['default', 'console'],  #
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)传递
        },
        'l2: {
            'handlers': ['default', 'console' ], 
            'level': 'DEBUG',
            'propagate': False,  # 向上(更高level的logger)传递
        },
        'l3': {
            'handlers': ['default', 'console'],  #
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)传递
        },

}

    
#我们的解决方式是,定义一个空的key
    'loggers': {
        '': {
            'handlers': ['default', 'console'], 
            'level': 'DEBUG',
            'propagate': True, 
        },

}

这样我们再取logger对象时
logging.getLogger(__name__),不同的文件__name__不同,这保证了打印日志时标识信息不同,但是拿着该名字去loggers里找key名时却发现找不到,于是默认使用key=''的配置
log配置字典相关问题

2.示例

|----示例
|    |---bin
|    |    |----start.py  #启动文件
|    |
|    |---conf
|    |    |----settings.py   #配置文件(logging配置)
|    |
|    |---core
|    |    |----  src.py   #业务核心逻辑
|    |
|    |---lib
|    |    |---- common.py    #公共库
|    |
|    |---  log    #日志
import os

BASE_DIR=os.path.dirname(os.path.dirname(__file__))


standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                  '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'


# log文件的全路径
fh1_logfile_path = r'%s\%s\%s' %(BASE_DIR,'log','b1.log')
fh2_logfile_path = r'%s\%s\%s' %(BASE_DIR,'log','b2.log')

# log配置字典
LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
    },
    'filters': {},
    'handlers': {
        #打印到终端的日志,使用的格式为 simple_format
        'ch': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'
        },
        #打印到文件b1.log的日志,使用的格式为 standard_format
        'fh1': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',  # 保存到文件
            'formatter': 'standard',
            'filename': fh1_logfile_path,  # 日志文件
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
        #打印到文件b2.log的日志,使用的格式为 standard_format
        'fh2': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',  # 保存到文件
            'formatter': 'standard',
            'filename': fh2_logfile_path,  # 日志文件
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
    },
    'loggers': {
        '': {
            'handlers': ['ch', 'fh1','fh2'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}
settings配置
from conf import settings
import logging.config

def get_logger(name):
    logging.config.dictConfig(settings.LOGGING_DIC)
    logger1=logging.getLogger(name)
    return logger1
common.py
from lib import common

logger1=common.get_logger("交易日志")

def shopping():
    print('购物')

def pay():
    print('支付')
    logger1.info('蘑菇 支付了1元')

def transfer():
    print('转账')
    logger1.info('蘑菇给小火柴支付了200元')


def withdraw():
    print('提现')
    logger1.info('蘑菇提现200元')

func_dic={
    '1': shopping,
    '2': pay,
    '3': transfer,
    '4': withdraw
}

def run():
    while True:
        print("""
        0 退出
        1 购物
        2 支付
        3 转账
        4 提现
        """)
        choice=input('请输入您的操作: ').strip()
        if choice == '0':break
        if choice not in func_dic:
            print("输入的指令不存在,请重新输入")
            continue
        func_dic[choice]()
src.py
import sys
import os

BASE_DIR=os.path.dirname(os.path.dirname(__file__))
sys.path.append(BASE_DIR)

from core import src

if __name__ == '__main__':
    src.run()
start.py

五、re 模块(正则匹配)

 一、什么是正则

正则就是 用一些具体特殊含义的符号组合到一起(称为正则表达式)来描述字符或字符串的方法。或者说正则就是用来描述一类事物的规则。python中,它内嵌在python中,并通过re模块实现。

正则表达式被编译成一系列的字节码,然后由C编写的匹配引擎执行。

生活中处处是正则:

  比如我们描述:4条腿

    就会想到四条腿的动物或者桌子,椅子

  再描述:四条腿,活的

    就只有四条腿的动物这类

二、常用匹配模式(元字符)

#==========================re模块  正则表达式=============================
import re
#1、 \w匹配数字字母下划线
print(re.findall('\w','hello 123 - _ *()'))
#['h', 'e', 'l', 'l', 'o', '1', '2', '3', '_']
print(re.findall('mogu','hello mogu, mogu say hello'))#前面mogu代表完全匹配
#['mogu', 'mogu']

#2、 \W 上方的取反
print(re.findall('\W','hello 123 - _ *()'))
#[' ', ' ', '-', ' ', ' ', '*', '(', ')']

#3、 \s 匹配任意空白字符
print(re.findall('\s','666 \t jiayou'))
#[' ', '\t', ' ']
#    \S 上方取反

#4、 \d 匹配任意数字   \D 取反匹配任意数字
print(re.findall('\d','666 \t jia\nyou'))
#['6', '6', '6']

#5、 \n 只匹配换行符, \t 只匹配制表符
print(re.findall('\n','666 \t jia\nyou'))
print(re.findall('\t','666 \t jia\nyou'))
#['\n']
#['\t']

#6、 ^ 匹配字符串的开头   $ 匹配字符串的结尾
print(re.findall('^mogu','hello mogu, mogu say hello'))
print(re.findall('mogu$','hello mogu, mogu say hello mogu'))
# ^结果为空 只匹配开头
# $ ['mogu']  只匹配匹配末尾

#7、 . :点 代表匹配除了换行符以外的任意单个字符
print(re.findall('a.c','a-c a*c a2c a\nc aacacacacac a c a\tc',re.DOTALL))
# ['a-c', 'a*c', 'a2c', 'aac', 'a c', 'a\tc']
# re.DOTALL  可以让换行符也匹配出来

#8、 [] : 代表匹配指定范围的任意字符
print(re.findall('\d[-+*/]\d','1+2 3!3 qweasd 2+3 1/2 2-3 axcz hello'))
#['1+2', '2+3', '1/2', '2-3']
print(re.findall('a[0-9]c','a1c aAc a2c acc axc a23c a*c a9c'))
#['a1c', 'a2c', 'a9c']
print(re.findall('a[0-9][0-9]c','a1c aAc a2c acc axc a23c a*c a9c'))
#['a23c']
print(re.findall('a[a-z]c','a1c aAc a2c acc axc a23c a*c a9c'))
#['acc', 'axc']
print(re.findall('a[A-Z]c','a1c aAc a2c acc axc a23c a*c a9c'))
#['aAc']

#9、重复匹配
#9.1  ? : 代表左边那一个字符出现0次或者1次 可以用{0,1}
print(re.findall('ab?','b ab abb bbabbabbabba'))
#['ab', 'ab', 'ab', 'ab', 'ab', 'a']

#9.2  * :代表左边那一个字符出现0次或者无穷次,如果没有可以凑合,但如果>1个,有多少就必须拿多少
#   可以用{0,}
print(re.findall('ab*','b ab abb bbabbababba'))
#['ab', 'abb', 'abb', 'ab', 'abb', 'a']

#9.3  + :代表左边那一个字符出现1次或者无穷次,至少要有一个,但如果有>1个,有多少就必须拿多少
#   可以用{1,}
print(re.findall('ab+','b ab abb bbabbabbabba'))
#['ab', 'abb', 'abb', 'abb', 'abb']

#9.4 {n,m}:代表左边那一个字符出现n次到m次,至少要有n个,但如果有>n个,就拿<=m个
print(re.findall('ab{2,5}','b ab abb bbabbabbabba abbbbbbbb'))
#['abb', 'abb', 'abb', 'abb', 'abbbbb']

#9.5  .* : 匹配0个或无穷个任意字符,默认是贪婪匹配
print(re.findall('a.*c','a123c hello ab123  c321 mogu c'))
# ['a123c hello ab123  c321 mogu c'] 找离a最远的c

#9.6  .*? : 匹配0个或无穷个任意字符,非贪婪匹配
print(re.findall('a.*?c','a123c hello ab123  c321 mogu c'))
#['a123c', 'ab123  c']  找离a最近的c

#示例: 正则使用非贪婪匹配 ()括号的意思是  只取分组内的内容
print(re.findall('href="(.*?)"',''
    '<div class="div1"><a href="https://www.baidu.com">点我啊</a>'
    '</div><div class="div1"><a href="https://www.python.org">点我啊</a></div>'))
#[]
print(re.findall('a[1*-]b','a1b a*b a-b')) #[]内的都为普通字符了,且如果-没有被转意的话,应该放到[]的开头或结尾
print(re.findall('a[^1*-]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[0-9]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #[]内的^代表的意思是取反,所以结果为['a=b']

#\# print(re.findall('a\\c','a\c')) #对于正则来说a\\c确实可以匹配到a\c,但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常
print(re.findall(r'a\\c','a\c')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义
print(re.findall('a\\\\c','a\c')) #同上面的意思一样,和上面的结果一样都是['a\\c']

#():分组
print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab
print(re.findall('(?:ab)+123','ababab123')) #findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容
print(re.findall('href="(.*?)"','<a href="http://www.baidu.com">点击</a>'))#['http://www.baidu.com']
print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com">点击</a>'))#['href="http://www.baidu.com"']

#|
print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
补充
import re
#1 findall
print(re.findall('e','mogu like read') )   #['e', 'e'],findall返回所有满足匹配条件的结果,放在列表里
#2 search
print(re.search('e','mogu like read').group())# e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。

#3 match
print(re.match('e','mogu like read'))    #None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match

#4 split
print(re.split('[ ]','mogu like read'))     #['mogu', 'like', 'read'],先按'空格'分割得到'mogu' 'like' 'read'

#5
print('===>',re.sub('m','M','mogu like read movie')) #===> Mogu like read Movie,不指定n,默认替换所有
print('===>',re.sub('m','M','mogu like read movie',1)) #===> Mogu like read movie
print('===>',re.sub('m','M','mogu like read movie',2)) #===> Mogu like read Movie
print('===>',re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','mogu like read movie')) #===> read like mogu

print('===>',re.subn('m','M','mogu like read movie')) #===> ('Mogu like read Movie', 2),结果带有总共替换的个数

#6
obj=re.compile('\d{2}')  #封装一种正则匹配模式

print(obj.search('abc123eeee').group()) #12
print(obj.findall('abc123eeee')) #['12'],重用了obj

#=======================================
print(re.findall(r'-?\d+\.?\d*',"1-12*(60+(-40.35/5)-(-4*3))")) #找出所有数字['1', '-12', '60', '-40.35', '5', '-4', '3']


#使用|,先匹配的先生效,|左边是匹配小数,而findall最终结果是查看分组,所有即使匹配成功小数也不会存入结果
#而不是小数时,就去匹配(-?\d+),匹配到的自然就是,非小数的数,在此处即整数
print(re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")) #找出所有整数['1', '-2', '60', '', '5', '-4', '3']
re模块的方法
#为何同样的表达式search与findall却有不同结果:
print(re.search('\(([\+\-\*\/]*\d+\.?\d*)+\)',"1-12*(60+(-40.35/5)-(-4*3))").group()) #(-40.35/5)
print(re.findall('\(([\+\-\*\/]*\d+\.?\d*)+\)',"1-12*(60+(-40.35/5)-(-4*3))")) #['/5', '*3']

#看这个例子:(\d)+相当于(\d)(\d)(\d)(\d)...,是一系列分组
print(re.search('(\d)+','123').group()) #group的作用是将所有组拼接到一起显示出来
print(re.findall('(\d)+','123')) #findall结果是组内的结果,且是最后一个组的结果
findall与search

总结

尽量精简,详细的如下

尽量使用泛匹配模式.*

尽量使用非贪婪模式:.*?

使用括号得到匹配目标:用group(n)去取得结果

有换行符就用re.S:修改模式

在线测试 :正则测试

六、time与datetime模块

在Python中,通常有这几种方式来表示时间:

  • 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
  • 格式化的时间字符串(Format String)
  • 结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
import time
#--------------------------当前时间为准,三种形式的时间 print(time.time()) # 时间戳:1536155758.0554852 print(time.strftime("%Y-%m-%d %X")) #格式化的时间字符串:'2018-09-05 21:55:58' print(time.localtime()) #本地时区的struct_time print(time.gmtime()) #UTC时区的struct_time
%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.     
%d    Day of the month as a decimal number [01,31].     
%H    Hour (24-hour clock) as a decimal number [00,23].     
%I    Hour (12-hour clock) as a decimal number [01,12].     
%j    Day of the year as a decimal number [001,366].     
%m    Month as a decimal number [01,12].     
%M    Minute as a decimal number [00,59].     
%p    Locale’s equivalent of either AM or PM.    (1)
%S    Second as a decimal number [00,61].    (2)
%U    Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0.    (3)
%w    Weekday as a decimal number [0(Sunday),6].     
%W    Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0.    (3)
%x    Locale’s appropriate date representation.     
%X    Locale’s appropriate time representation.     
%y    Year without century as a decimal number [00,99].     
%Y    Year with century as a decimal number.     
%z    Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59].     
%Z    Time zone name (no characters if no time zone exists).     
%%    A literal '%' character.
格式化字符串的时间格式

 

其中计算机认识的时间只能是'时间戳'格式,而程序员可处理的或者说人类能看懂的时间有: '格式化的时间字符串','结构化的时间' 

import time
#--------------------------按图1转换时间
 # localtime([secs])
 # 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
time.localtime()
time.localtime(1473525444.037215)

# gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。

# mktime(t) : 将一个struct_time转化为时间戳。
print(time.mktime(time.localtime()))#1536156163.0


# strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和
# time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个
# 元素越界,ValueError的错误将会被抛出。
print(time.strftime("%Y-%m-%d %X", time.localtime()))#2018-09-05 22:02:43

# time.strptime(string[, format])
# 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
print(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X'))
# time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, tm_wday=3, tm_yday=125, tm_isdst=-1)
#在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。

 

import time
#--------------------------按图2转换时间
# asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。
# 如果没有参数,将会将time.localtime()作为参数传入。
print(time.asctime())#Wed Sep  5 22:06:41 2018

# ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为
# None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
print(time.ctime())  # Wed Sep  5 22:06:41 2018
print(time.ctime(time.time()))  # Wed Sep  5 22:06:41 2018
#时间加减
import datetime,time


print(datetime.datetime.now()) #返回 2018-09-05 22:08:48.246537
print(datetime.date.fromtimestamp(time.time()) )  # 时间戳直接转成日期格式 2018-09-05
# 
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)) #时间替换
datetime模块!!!

七、序列化(json与pickle)模块

1、什么是序列化

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

2、为什么要序列化

持久保存状态

需知一个软件/程序的执行就在处理一系列状态的变化,在编程语言中,'状态'会以各种各样有结构的数据类型(也可简单的理解为变量)的形式被保存在内存中。

内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。

在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。

具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。

跨平台数据交互

序列化之后,不仅可以把序列化后的内容写入磁盘,还可以通过网络传输到别的机器上,如果收发的双方约定好实用一种序列化的格式,那么便打破了平台/语言差异化带来的限制,实现了跨平台数据交互。

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

3、如何序列化之json和pickle

json

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

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

 

 

# =======================序列化与反序列化方法一  json.dumps=======================
import json
user_dict={}
name=input('名字:').strip()
age=input('年龄:').strip()
user_dict['name']=name
user_dict['age']=age
user_dict['is_beautiful']=True
print(user_dict)  #{'name': 'mogu', 'age': '19', 'is_beautiful': True}
m=json.dumps(user_dict) # 这一步。。。
with open('%s.json'%name,'w') as f:
    f.write(m)
#==============================反序列化==========================================
name=input('名字:').strip()
with open('%s.json'%name,'r') as f:
    msg=json.loads(f.read())
print(msg)
json序列化方法一
# =======================序列化与反序列化方法二  json.dump=======================
import json
user_dict={}
name=input('名字:').strip()
age=input('年龄:').strip()
user_dict['name']=name
user_dict['age']=age
user_dict['is_beautiful']=True
print(user_dict)  #{'name': 'mogu', 'age': '19', 'is_beautiful': True}
#            这里无需再dumps
with open('%s.json'%name,'w') as f:
    json.dump(user_dict,f) #传对象与文件
# ==============================反序列化之 json.load==========================================
name=input('名字:').strip()
with open('%s.json'%name,'r') as f:
    msg=json.load(f)   #load  默认做了f.read()
print(msg)
json序列化方法二(实用)
import json
#dct="{'1':111}"#json 不认单引号
#dct=str({"1":111})#报错,因为生成的数据还是单引号:{'one': 1}

dct='{"1":"111"}'
print(json.loads(dct))

#conclusion:
#        无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
注意点!!!

pickle

# =======================序列化与反序列化 pickle.dumps=======================
import pickle

user_dict={}
name=input('名字:').strip()
age=input('年龄:').strip()
user_dict['name']=name
user_dict['age']=age
user_dict['is_beautiful']=True
print(user_dict)  #{'name': 'mogu', 'age': '19', 'is_beautiful': True}
m=pickle.dumps(user_dict) #序列化得到bytes
with open('%s.pickle'%name,'wb')as f:  #注意w是写入str,wb是写入bytes,m是'bytes'
    f.write(m)
# ==============================反序列化之 pickle.loads==========================================
name=input('名字:').strip()
with open('%s.pickle'%name,'rb') as f:
    msg=pickle.loads(f.read())
print(msg)

方法其实与 json  一模一样

 Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。

八、hashlib模块

1、什么叫hash:

hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的内容,经过运算得到一串hash值。

2、hash的特点是:

2.1 只要传入的内容一样,得到的hash值必然一样 -----> 要用明文传输密码文件完整性校验
2.2 不能由hash值返解成内容 -------> 把密码做成hash值,不应该在网络传输明文密码
2.3 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的

hash算法就像一座工厂,工厂接收你送来的原材料(可以用m.update()为工厂运送原材料),经过加工返回的产品就是hash值

import hashlib

m=hashlib.md5()# m=hashlib.sha256()

m.update('hello'.encode('utf8'))
print(m.hexdigest())  #5d41402abc4b2a76b9719d911017c592
m.update('world'.encode('utf8'))

print(m.hexdigest())  #fc5e038d38a57032085441e7fe7010b0

m2=hashlib.md5()
m2.update('helloworld'.encode('utf8'))
print(m2.hexdigest()) #fc5e038d38a57032085441e7fe7010b0

'''
注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样
但是update多次为校验大文件提供了可能。 
'''

以上加密算法虽然依然非常厉害,但存在缺陷,即:通过撞库(碰撞)可以反解。所以,有必要对加密算法中添加自定义key(加盐)再来做加密。

import hashlib

m=hashlib.md5()
m.update('world'.encode('utf8')) #7d793037a0760186574b0282f2f435e7
print (m.hexdigest())

x = hashlib.md5('天王盖地虎'.encode('utf8'))
x.update('world'.encode('utf8')) #26d7f494fd36ebcb1572fd41e5305b67
print (x.hexdigest())
import hashlib
passwds=[
    '123456',
    '96875643',
    'qweasd321',
    'qaz987321',
    '741852asd',
    'zxc654123',
    ]
def make_passwd_dic(passwds):
    dic={}
    for passwd in passwds:
        m=hashlib.md5()
        m.update(passwd.encode('utf-8'))
        dic[passwd]=m.hexdigest()
    return dic

def break_code(cryptograph,passwd_dic):
    for k,v in passwd_dic.items():
        if v == cryptograph:
            print('密码是===>\033[46m%s\033[0m' %k)

cryptograph='6d57314243f721a1bbddb9ca405f285d'  #截取加密后的密文进行撞库(比如说密码是qaz987321)
break_code(cryptograph,make_passwd_dic(passwds))
模拟撞库破解密码

hmac 模块

python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密:

import hmac
h = hmac.new('天王盖地虎'.encode('utf8'))
h.update('hello'.encode('utf8'))
print (h.hexdigest())#1abaae8f65f68f2695a8545c5bc8e738

#要想保证hmac最终结果一致,必须保证:
#1:hmac.new括号内指定的初始key一样
#2:无论update多少次,校验的内容累加到一起是一样的内容

九、OS模块

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

import os
BASE=os.path.dirname(__file__)
path=os.path.join(BASE,'dbpath')

os.getcwd()         #获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dbpath")  #改变当前脚本工作目录;相当于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(path+r'\test.py')       #  删除一个文件
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.environ()               # 获取系统环境变量
os.popen(command[, mode[, bufsize]])  # 方法用于从一个命令打开一个管道。
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的大小
#==========================================
os.walk()    #方法是一个简单易用的文件、目录遍历器,可以帮助我们高效的处理文件、目录方面的事情。
#os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])参数
#top     -- #是你所要遍历的目录的地址, 返回的是一个三元组(root,dirs,files)。
    #root 所指的是当前正在遍历的这个文件夹的本身的地址
    #dirs 是一个 list ,内容是该文件夹中所有的目录的名字(不包括子目录)
    #files 同样是 list , 内容是该文件夹中所有的文件(不包括子目录)
#topdown -- 可选, 为 True,则优先遍历 top 目录,否则优先遍历 top 的子目录(默认为开启)。如果 topdown 参数为 True,walk 会遍历top文件夹,与top 文件夹中每一个子目录。
#onerror -- 可选, 需要一个 callable 对象,当 walk 需要异常时,会调用。
#followlinks -- 可选, 如果为 True,则会遍历目录下的快捷方式(linux 下是 symbolic link)实际所指的目录(默认关闭)。
OS模块常用方法
os路径处理
#方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
    os.path.abspath(__file__),
    os.pardir, #上一级
    os.pardir,
    os.pardir
))
sys.path.insert(0,possible_topdir)


#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

十、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       返回操作系统平台名称
#=========知识储备==========
#进度条的效果
[#             ]
[##            ]
[###           ]
[####          ]

#指定宽度
print('[%-15s]' %'#')
print('[%-15s]' %'##')
print('[%-15s]' %'###')
print('[%-15s]' %'####')

#打印%
print('%s%%' %(100)) #第二个%号代表取消第一个%的特殊意义

#可传参来控制宽度
print('[%%-%ds]' %50) #[%-50s]
print(('[%%-%ds]' %50) %'#')
print(('[%%-%ds]' %50) %'##')
print(('[%%-%ds]' %50) %'###')


#=========实现打印进度条函数==========
import sys
import time

def progress(percent,width=50):
    if percent >= 1:
        percent=1
    show_str=('[%%-%ds]' %width) %(int(width*percent)*'#')
    print('\r%s %d%%' %(show_str,int(100*percent)),file=sys.stdout,flush=True,end='')


#=========应用==========
data_size=1025
recv_size=0
while recv_size < data_size:
    time.sleep(0.1) #模拟数据的传输延迟
    recv_size+=1024 #每次收1024

    percent=recv_size/data_size #接收的比例
    progress(percent,width=70) #进度条的宽度70
打印进度条
def __progress(self, recv_size, data_size, width=70):
        ''' =========进度条==========
    # data_size = 9292
    # recv_size = 0
    # while recv_size < data_size:
    #     time.sleep(0.1)  # 模拟数据的传输延迟
    #     recv_size += 1024  # 每次收1024
    #
    #     percent = recv_size / data_size  # 接收的比例
    #     progress(percent, width=70)  # 进度条的宽度70'''
        percent = float(recv_size) / float(data_size)
        if percent >= 1:
            percent = 1
        show_str = ('[%%-%ds]' % width) % (int(width * percent) * '>')
        print('\r%s %d%%' % (show_str, int(100 * percent)), file=sys.stdout, flush=True, end='')

#==================================
self.__progress(receive_size, file_size)#接受大小,总文件大小
FTP应用

十一、random模块

import random

print(random.random())#(0,1)----float    大于0且小于1之间的小数
print(random.randint(1,3))  #[1,3]    大于等于1且小于等于3之间的整数

print(random.randrange(1,3)) #[1,3)    大于等于1且小于3之间的整数

print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5]

print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合

print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716


item=[1,3,5,7,9]
random.shuffle(item) #打乱item的顺序,相当于"洗牌"
print(item)
import random
def make_code(n):
    res=''
    for i in range(n):
        s1=chr(random.randint(65,90)) #chr 代表参照ASCII表 转成对应字符
        s2=str(random.randint(0,9))   
        res+=random.choice([s1,s2]) #取随机数拼凑
    return res

print(make_code(4))
随机验证码

十二、其余模块加内置函数

 链接地址:https://www.cnblogs.com/nixindecat/p/9599829.html

posted @ 2018-08-27 15:52  xiaomogugu  阅读(424)  评论(0编辑  收藏  举报