Python学习笔记 - day9 - 模块与包

模块与包

一个模块就是一个包含了Python定义和声明的文件,文件名就是模块名加上.py的后缀,导入一个py文件,解释器解释该py文件,导入一个包,解释器解释该包下的 __init__.py 文件,所以如果我们要创建一个包文件,那么该文件下必须要有__init__.py文件。

从目录级别来组织模块的,本质上也是被导入的,目录下有 __init__ 文件的都可以理解为包,在import时,其实导入的就是包下的 __init__.py 文件。

  • 无论是import形式,还是from...import形似,凡是在导入语句中(而不是使用时)遇到带点的,就是在导入包
  • 包是目录级的(文件夹),文件夹是用来组织py文件的。(包的本质就是一个包含 __init__.py 文件的目录)
  • import导入文件时,产生的名称空间来源于文件,import包,产生的命名空间同样来源于文件,既包下面的__init__.py,导入包的本质就是导入该文件

包的import *

这个* 其实读取的就是 __init__ 文件里面的所有函数,所以一般不要用*
通过在父包内的__init__文件中利用相对路径进行导入子包的模块或者方法,来达到通过(父包.方法)来调用,屏蔽了不同子包路径过长的问题

模块

要想使用模块需要先行倒入,那么根据导入方式的不同主要有两种方式:import 和 from。

import导入

导入操作:
  1)import导入模块就会执行要导入的模块的所有代码
  2)产生新的名称空间
  3)拿到一个模块名,指向模块中的代码
语法:

import module as alias  # 导入时并定义别名
import module,module1,module2  # 一次导入多个模块(不建议)

调用方式:使用包名.函数名来执行导入的函数

import time
print(time.strftime('%Y-%m-%d %H:%M:%S'))

# 导入time模块
# 使用 time.strftime()来调用strftime()函数

注意:使用import方式会导入包中的所有函数。

from导入      

导入操作:
  1)会执行要导入的模块的所有代码,调用时只通过func就可以调用
  2)如果func和本文件中存在同名func,那么就会覆盖
语法:

from module import func  # 调用时可以直接使用func,而不必使用module.func来调用
from module import * # 导入所有函数

PS:在被导入模块的__init__.py文件中定义__all__ = ['module','module1'],这样在导入其时,用*,只能导入 __all__ 定义的模块

调用方式:直接使用函数名进行调用。 

from time import strftime
print(strftime('%Y-%m-%d %H:%M:%S'))

PS:func来自哪个文件,那么func内部调用的变量,以其所在文件中的环境变量为准

模块中的特殊关键字及路径

模块文件中有一些Python提供的特殊关键字,例如
__file__ :打印当前文件的文件名
__name__ :显示当前模块是否被导入,显示:__main__ 表示没有被导入,显示:模块名, 表示被此模块被导入。
PS:如果我们写的Python文件中的某个函数或者类会被其他人调用,使用if __name__ == '__main__' ,后面写主逻辑,这样在别的地方导入,就不会执行下面的代码段,而直接运行文件时,就会执行。

模块路径      

顾名思义,导入模块是需要先找到该模块,和在linux中执行命令是相同的,在Python中导入模块的搜索顺序:

  1. 先从内存中寻找
  2. 然后在内置模块中寻找
  3. 然后在sys.path中查找

关于sys.path,类似于shell中的PATH,其是list类型,每个元素为路径的字符串形式,列表的第一个路径默认为当前路径,使用sys.path.append('dirpath'),就可以把路径加入到sys.path中

Python内置模块 

Python中内置了很多模块,可以提供很多实用的功能,下面将会列举部分模块。

datetime模块

提供时间功能的模块其实不止datetime,Python内置的还有一个time模块,time模块可以完成格式化输出,但是用起来没有datetime模块方便,但在下面场景下会用到time模块

import time
for i in range(1,10):
    print(i)
    time.sleep(1)     # 类似于Linux中的sleep命令。

获取当前日期和时间

datetime.now() 格式化输出一个datetime.datetime对象,打印则显示当前时间

from datetime import datetime
print(type(datetime.now()))
print(datetime.now())

注意到datetime是模块,datetime模块还包含一个datetime类,通过from datetime import datetime导入的才是datetime这个类,如果仅导入import datetime,则必须引用全名datetime.datetime.now()

获取指定的日期与时间

通过是datetime对象实例化的时候,传入指定的时间参数,来获取指定的日期与时间的时间格式字符。

from datetime import  datetime

timer = datetime(2017,11,9,11,20)
print(timer)

注意:时间日期如果是个位数,不能手动补0,比如9可以,09就不行。

获取时间戳

在计算机中,时间实际上是用数字表示的。我们把1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time(元时间),记为0(1970年以前的时间timestamp为负数),当前时间就是相对于epoch time的秒数,称为timestamp(时间戳)。

  • 所以针对于元时间来说:timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
  • 对应的北京时间是:timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00(因为北京属于东八区)

可见timestamp的值与时区毫无关系,因为timestamp一旦确定,其UTC时间就确定了,转换到任意时区的时间也是完全确定的,这就是为什么计算机存储的当前时间是以timestamp表示的,因为全球各地的计算机在任意时刻的timestamp都是完全相同的(假定时间已校准)。

from datetime import datetime

print(datetime.now().timestamp())

# 注意 timestamp(),方法可以作用在datetime.datetime对象上。 (datetime(2017,11,9,11,50)因为返回的是datetime.datetime对象,所以也可以使用timestamp()来转换)

时间戳转换为格式化时间

要把timestamp转换为datetime,使用datetime提供的fromtimestamp()方法:

from datetime import datetime
t = datetime.now().timestamp()
print(t)
t2 = datetime.fromtimestamp(t)
print(t2) 

注意到timestamp是一个浮点数,它没有时区的概念,而datetime是有时区的。上述转换是在timestamp和本地时间做转换。如果我们计算机本地时间为 UTC +8,那么获得的时间就是基于本地UTC时间的。

获取前几个小时或后几天

获取前几个小时或后几天,其实是对日期和时间进行加减,得到新的datetime。加减可以直接用+-运算符,不过需要导入timedelta这个类:

from datetime import  datetime,timedelta

now = datetime.now()

timer = now - timedelta(hours=10)

print(timer)

# timedelta 默认为天,其他参数还有 days,hours,minutes等。
# 传递的参数可以为负数

datetime对象转换为字符串时间

如果已经有了datetime对象,要把它格式化为一个特定的字符串显示给用户,就需要转换为str,转换方法是通过strftime()实现的,同样需要一个日期和时间的格式化字符串:

from datetime import  datetime

str_time = datetime.now().strftime('%Y-%M-%d %H:%M:%S')

print(str_time)

字符串时间转换为datetime对象

很多时候,用户输入的日期和时间是字符串,要处理日期和时间,首先必须把str转换为datetime。转换方法是通过datetime.strptime()实现,需要一个日期和时间的格式化字符串:‘

from datetime import datetime

str_time = '2017-11-09 17:15:48'

date_time = datetime.strptime(str_time,'%Y-%m-%d %H:%M:%S')
print(date_time)

logging模块

logging模块用于日志的打印记录等,是一个健壮的Python程序所必须具有的模块。

logging模块支持的日志级别主要有五种:DEBUG,INFO,WARNING,ERROR,CRITICAL。优先级为:CRITICAL > ERROR > WARNING > INFO > DEBUG 。 默认的级别为WARNING。Python只会打印比当前级别高的日志,比如我同时刷出了INFO和ERROR级别的日志,如果我的日志级别设置的为WAIRNING,那么只会打印ERROR的日志。

基本使用

引入logging模块,通过logging.级别来输出日志信息

import logging

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

注意:由于默认级别为WARNING,所以上面的例子只会打印WARNING、ERROR、CRITICAL输出的信息

定义日志格式并输出到文件

logging提供了基础的日志模版,可以定义日志的输出格式,以及输出位置

import logging


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

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

basicConfig支持的参数含义为:

  • level:为日志级别,可选参数有logging.DEBUG,logging.INFO,logging.WARNING,logging.ERROR,logging.CRITICAL,分别对应logging的五种日志级别。
  • filename: 表示日志文件的名称及路径。
  • filemode: 表示日志文件的打开模式,默认不指定的情况下为a,可以改为w。
  • datefmt: 对时间进行格式定制,和时间的格式化字符是相同的。
  • format: 对日志格式进行定义。
 1 %(name)s  # Logger的名字
 2 %(levelno)s  # 数字形式的日志级别
 3 %(levelname)s # 文本形式的日志级别
 4 %(pathname)s # 调用日志输出函数的模块的完整路径名,可能没有
 5 %(filename)s # 调用日志输出函数的模块的文件名
 6 %(module)s # 调用日志输出函数的模块名
 7 %(funcName)s # 调用日志输出函数的函数名
 8 %(lineno)d # 调用日志输出函数的语句所在的代码行
 9 %(created)f # 当前时间,用UNIX标准的表示时间的浮 点数表示
10 %(relativeCreated)d # 输出日志信息时的,自Logger创建以 来的毫秒数
11 %(asctime)s # 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
12 %(thread)d # 线程ID。可能没有
13 %(threadName)s # 线程名。可能没有
14 %(process)d # 进程ID。可能没有
15 %(message)s # 用户输出的消息
format支持的日志格式

当然logging还有更多灵活的模块:logger,handler,filter,formatter。参考:http://www.jb51.net/article/88449.htm 

多模块利用logging记录日志

我们可以把logging写到一个模块中,然后在需要记录的地方,导入模块,记录信息即可。

# writelog模块:
import logging

logging.basicConfig(level=logging.WARNING,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    filename='log.log',
                    filemode='a')




# 需要记录日志的py文件
import writelog

writelog.logging.debug('debug level message')
writelog.logging.info('info level message')
writelog.logging.warning('warning level message')
writelog.logging.error('error level message')
writelog.logging.critical('crtical level message')

OS模块 

OS模块简单的来说它是一个Python的系统编程的操作模块,可以处理文件和目录这些我们日常手动需要做的操作,和所在的操作系统版本无关。

查看OS模块的帮助文档

>>> import os  # 导入os模块
>>> help(os)   # 查看os模块帮助文档,里面详细的模块相关函数和使用方法

常用功能介绍 

os模块中提供了特别多的和系统相关的操作功能,这里列举一些常用功能 

os.getcwd()   # 获取当前路径
os.chdir()  # 切换当前目录,当路径中存在\的时候,由于是转意的意思,那么就需要对\进行转意,那么路径就是c:\\User,或者在目录前面加r,表示后面的字符串不进行解释
os.curdir()  # 获取当前目录名
os.pardir()  # 获取上级目录名
os.mkdir('dir')  # 创建目录,注意只能创建一级目录
os.makedirs('dir_path')  # 创建多级目录
os.rmdir('dir')  # 删除一个目录
os.removedir('dir_path')  # 删除多级目录(目录为空的话)
os.listdir('dir')  # 显示目录下的所有文件,默认为当前目录,返回的结果为list
os.remove('file')  # 删除一个文件
os.rename('old_name','new_name')  # 修改文件名称
os.stat('file/dir')  # 获取文件/目录的stat信息
os.sep  # 返回当前操作系统的路径分隔符
# Windows下:\\ , Linux下:/
os.linesep  # 返回当前操作系统的换行符
# Windows下:\r\n  ,Linux下:\n
os.pathsep  # 返回当前操作系统环境变量分隔符
# Windows下:;   ,   Linux下: :
os.name  # 返回当前系统的类型
# nt 表示Windows,  posix表示Linux
os.system('Commmand')  # 执行命令
os.environ  # 获取系统环境变量,使用字典存储
os.path.abspath('dir/file')  # 获取dir/file的绝对路径
os.path.split('path')  # 把路径分割为目录和文件名组成的元组格式,不管path是否存在
os.dirname('path')  # 获取文件的父目录名称,不管path是否存在
os.basename('path')  # 获取文件的名称,不管path是否存在
os.path.exists('path')  # 判断path是否存在,return bool
os.path.isabs('path')  # 判断path是否是从根开始,return bool
# Linux下:从/开始    Windows下从C,D,E盘开始
os.path.isfile('path')  # 判断path是否是一个文件
os.path.isdir('path')  # 判断path是否是一个目录
os.path.join('path1','path2')  # 把path1和path2进行组合
os.path.getatime('path')  # 获取文件的atime时间,返回时间戳
os.path.getmtime('path')  # 获取文件的mtime时间,返回时间戳
os.path.getsize('name')  # 获取文件的大小

commands模块

commands模块专门用于调用Linux shell命令,并返回状态和结果,和os的popen功能类似,该模块一共有三个函数:getoutput,getstatus,getstatusoutput

commands.getoutput('Linux shell command')   # 执行Linux shell命令,并获取命令执行的结果
commands.getstatus('filename')    # 传递filename,执行 'ls -ld  filename' 的命令。
commands.getstatusoutput('Linux shell command')   # 执行Linux shell命令,返回的是一个元组.。(命令返回code,结果)

实例:

>>> import commands
>>> commands.getoutput('who')
'DahlHin  console  Nov  9 09:38 \nDahlHin  ttys000  Nov 10 10:30 '
>>> commands.getstatus('.pip')
'drwxr-xr-x  3 DahlHin  staff  96 10 21 21:44 .pip'
>>> commands.getstatusoutput('asasas')
(32512, 'sh: asasas: command not found')
>>> 

注意:commands模块在Python 3.x中已经被subprocess替代!

sys模块

sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。 

常用函数:

sys.path # 列出当前Python环境变量,也就是导入时模块的搜索路径
sys.argv # 类似于shell脚本的$1 $2 ,用于传递命令行参数,使用列表进行传递
sys.stdout.write(‘#’) # 在屏幕上输出,但是不换行,配合for循环,比较适合用来做进度条等
sys.stdout.flush() # 配合sys.stdout.write使用,把每次输出的信息,强制刷新到屏幕上,达到动态的效果
1 import sys,time
2 for i in range(20):
3     sys.stdout.write('=')
4     sys.stdout.flush()
5     time.sleep(1)
进度条的动态效果

注意:我们可以把自己写的一些模块加到Python环境变量中去,由于sys.path是list类型,所以只需要append('path'),就可以完成添加。

 1 sys.modules.keys() # 返回所有已经导入的模块列表
 2 sys.exc_info()  # 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息
 3 sys.exit(n)  # 退出程序,正常退出时exit(0)
 4 sys.hexversion  # 获取Python解释程序的版本值,16进制格式如:0x020403F0
 5 sys.version  # 获取Python解释程序的版本信息
 6 sys.maxint  # 最大的Int值
 7 sys.maxunicode  # 最大的Unicode值
 8 sys.modules  # 返回系统导入的模块字段,key是模块名,value是模块
 9 sys.platform # 返回操作系统平台名称
10 sys.stdout  # 标准输出
11 sys.stdin  # 标准输入
12 sys.stderr  # 错误输出
13 sys.exc_clear()  # 用来清除当前线程所出现的当前的或最近的错误信息
14 sys.exec_prefix  # 返回平台独立的python文件安装的位置
15 sys.byteorder  # 本地字节规则的指示器,big-endian平台的值是'big',little-endian平台的值是'little'
16 sys.copyright  # 记录python版权相关的东西
17 sys.api_version  # 解释器的C的API版本
其他的sys模块函数

json&pickle模块

json和pickle模块是用来做序列化的,为什么要序列化?序列化可以持久保存状态,还可以跨平台数据交互。

如何序列化?可以使用json或者pickle模块

  1. json(跨平台) 支持字典(dict)、列表(list)、字符串(str)、整型浮点型(int/float)、bool(True,False),null(None)。
  2. pickle(纯Python),可以序列化存储python所有的对象,甚至是一个函数,但是只能和Python程序进行交互,其他凭他不支持。

eval不能识别非Python语法的数据类型,所以很多时候要用json

json

json支持跨平台的序列化存储以及反序列化读取。

  • 序列化:dump,dumps
  • 反序列化:load,loads
1 # json.dumps 表示序列化,会返回一个序列化后的对象。
2 
3 import json
4 
5 a = [1,2,3,4]
6 
7 b = json.dumps(a)
8 
9 print(type(b))
json.dumps
 1 # json.dump 表示序列化存储到文件中去
 2 
 3 import json
 4 
 5 a = [1,2,3,4,5]
 6 
 7 with open('log.log','w') as f:
 8     json.dump(a,f)
 9 
10 
11 # dump 需要两个参数,持久化的存储的对象,第二个是一个可写的文件描述符。
json.dump
 1 # json.loads 从json字符串反序列化为对象
 2 import json
 3 
 4 a =  '[1, 2, 3, 4]'
 5 
 6 print(type(a))
 7 
 8 b = json.loads(a)
 9 
10 print(type(b))
11 
12 print(b)
json.loads
1 # json.load 从文件中反序列化为对象
2 import json
3 
4 with open('hello.txt','r') as f:
5     b = json.load(f)
6 
7 print(b)
json.load

pickle

pickle仅python支持,在序列化到文件中的时候没需要用b模式打开才可以。

  • 序列化:dump,dumps
  • 反序列化:load,loads
 1 # pickle.dumps 把对象序列化为bytes格式数据
 2 import pickle
 3 
 4 a = {
 5     'name':'daxin',
 6     'age':18,
 7     'job':'Linux'
 8 }
 9 
10 b = pickle.dumps(a)
11 print(b)
12 print(type(b))
pickle.dumps
 1 # pickle.dump 序列化到文件中
 2 import pickle
 3 
 4 a = {
 5     'name':'daxin',
 6     'age':18,
 7     'job':'Linux'
 8 }
 9 
10 with open('hello.txt','wb') as f:
11     pickle.dump(a,f)
pickle.dump
1 # pickle.loads 把bytes对象反序列化
2 import pickle
3 
4 b = b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x05\x00\x00\x00daxinq\x02X\x03\x00\x00\x00ageq\x03K\x12X\x03\x00\x00\x00jobq\x04X\x05\x00\x00\x00Linuxq\x05u.'
5 
6 a = pickle.loads(b)
7 
8 print(a)
pickle.loads
1 # pickle.load 从文件中反序列化
2 import pickle
3 
4 with open('hello.txt','rb') as f:
5     a = pickle.load(f)
6 
7 print(a)
pickle.load

注意:

  json序列化后的对象类型为str,pickle序列化后的对象类型为bytes,所以pickle序列化/反序列化时对文件的操作需要用b模式。

备份一个好用的json转换网站:https://www.json.cn/

random模块

顾名思义,用来产生随机数的模块,它有 如下几个常用的方法

random.randint(a,b)         # 在a,b之间随机选出一个数(包含a,b本身)
random.randrange(a,b,step)  # 这里和range的使用方法是相同的
random.choice(iterable)     # 在一个可迭代对象中随机选择
random.shuffle(seq)         # 原地对序列进行洗牌(随机打乱)

  

 

 

posted @ 2017-11-09 10:37  SpeicalLife  阅读(415)  评论(0编辑  收藏  举报