4.1 模块、包介绍和相关语法
- 4.2 time & datetime 模块
- 4.3 random 模块
- 4.4 os 模块
- 4.5 sys 模块
- 4.6 shutil 模块
- 4.7 json & pickle 模块
- 4.8 shelve 模块
- 4.9 xml 模块
- 4.10 ConfigParser 模块
- 4.11 hashlib 模块
- 4.12 subprocess 模块
- 4.13 logging 模块
- 4.14 re 模块
- 4.15 软件开发目录规范
- 4.16 本章小结
4.1模块、包介绍和相关语法
在Python中一个.py文件就称为一个模块(Module)
使用模块的好处
1.最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序时,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。
2.使用模块还可以避免函数名和变量名冲突。每个模块都有独立的命名空间,因此相同名字的函数和变量完全可以分别在不同的模块中,所以,我们在编写模块时,不必考虑名字会与其他模块冲突
模块分类
模块分为三种
内置标准模块(又称标准库)执行help('modules')查看所有python自带模块列表
- 第三方开源模块,可通过pip install 模块名 联网安装
- 自定义模块
模块调用
from module import xx
from module.xx.xx import xx as rename
from module.xx.xx import *
注意:模块一旦被调用,即相当执行了另外一个py文件里的代码
自定义模块
这个最简单,创建一个.py文件,就可以称之为模块,就可以在另外一个程序里导入
模块的查找路径
这与导入路径有关
import sys
print(sys.path)
输出
['', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']
python解释器会按照列表的顺序去依此到每个目录下去匹配你要导入的模块名,只要在一个目录下匹配到了该模块名,就会立刻导入,不在继续往后找。
注:列表第一个元素为空,即代表当前目录,所以 你自己定义的模块在当前目录会被优先导入。
开源模块的安装和使用
https://pypi.python.org/pypi 是python的开源模块库。
1.直接在上面这个页面上点download,下载后,解压并进入目录,执行以下命令完成安装
编译源码 python setup.py build
安装源码 python setup。py install
1.直接通过pip安装
pip3 install paramiko #paramiko 是模块名
pip命令会自动下载模块包并完成安装
软件一般会被自动安装你python安装目录这个子目录里
/your_python_install_path/3.6/lib/python3.6/site-packages
pip命令默认会连接在国外的python官方服务器下载,速度比较慢,你还可以使用国外的豆瓣源,数据会定期同步到国外官网,速度很快。
sudo pip install-i http://pypi.douban.com/simple/alex_sayhi --trusted-host pypi.douban.com #alex_sayhi是模块名
使用
下载后,直接导入使用就可以,跟自带模块调用办法无区别,演示连接Linux执行命令的模块
#coding:utf-8 import paramiko ssh=paramiko.SSHClient() ssh.set_missinig_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect('192.168.1.108',22,'alex','123') stdin,stdout,stderr=ssh.exec_command('df') print(stdout.read()) ssh.colse(); 执行命令-通过用户名和密码连接服务器
包(package)
当自己的模块文件越来越多,就需要对模块文件进行划分,比如把负责数据库交互的文件都放在一个文件夹,把与页面交互的文件放在一个文件夹。
. └── my_proj ├── crm #代码目录 │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ └── views.py ├── manage.py └── my_proj #配置文件目录 ├── settings.py ├── urls.py └── wsgi.py
像上边这样,一个文件夹管理多个模块文件,这个文件夹就称为包
不同包之间模块互相导入
crm/views.py内容
def sayhi(): print('hello world')
通过manage.py调用
form crm import views views.sayhi()
包就是文件夹,但该文件夹下必须存在_init_.py文件,该文件的内容可以为空。
_int_.py用于标识当前文件夹是一个包。
在crm目录下创建一个空文件_int_.py,执行代码
Alexs-MacBook-Pro:my_proj alex$ touch crm/__init__.py #创建一个空文件
Alexs-MacBook-Pro:my_proj alex$
Alexs-MacBook-Pro:my_proj alex$ ls crm/
__init__.py admin.py models.py views.py
__pycache__ apps.py tests.py views.pyc
Alexs-MacBook-Pro:my_proj alex$ python manage.py
hello world!
注意:在python3里,即使目录下没_int_.py文件也是能创建成功的,猜应该是解释器优化所致,但创建包还是要记得加上这个文件吧。
跨模块导入
. ├── __init__.py ├── crm │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ ├── views.py ├── manage.py └── proj ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
根据上面结构,如何实现在crm/views.py里导入proj/setting.py模块
直接导入会报错,说找不到模块
$ python3 views.py Traceback (most recent call last): File "views.py", line 2, in <module> from proj import settings ModuleNotFoundError: No module named 'proj'
是因为路径找不到,proj/setiting相当于crm/xiews.py的父亲(crm)的兄弟(proj)的儿子(setting.py),setting.py算是views.py的表弟了,在views.py里只能导入同级别兄弟模块代码,或者子级别包里的模块,根本不知道表弟表哥的存在。
答案是添加环境变量,把父亲级的路径添加到sys.path中,就可以了,这样导入 就相当于从父亲级开始找模块了。
crm/views.py中添加环境变量
import sys ,os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #__file__的是打印当前被执行的模块.py文件相对路径,注意是相对路径 print(BASE_DIR) sys.path.append(BASE_DIR) from proj import settings def sayhi(): print('hello world!') print(settings.DATABASES)
输出
$ python3 views.py /Users/alex/Documents/work/PyProjects/luffy_课件/21天入门/chapter4-常用模块/packages/my_proj ---my proj init--- #proj/__init__.py输出 in proj/settings.py #proj/settings.py输出 {'host': 'localhost'}
*注意;此时在proj/settings.py写上import urls会有问题么?
DATABASES= { 'host':'localhost' } import urls #这行刚加的 print('in proj/settings.py')
结果报错了
ModuleNotFoundError: No module named 'urls'
现在的程序入口是views.py , 你在settings.py导入import urls,其实相当于在crm目录找urls.py,而不是proj目录,若想正常导入,要改成如下
DATABASES= { 'host':'localhost' } from proj import urls #proj这一层目录已经添加到sys.path里,可以直接找到 print('in proj/settings.py')
绝对导入&相对导入
在Linux里可以通过cd..回到上一层目录,cd../..往上回两层,这个..就是指相对路径,在python里,导入也可以通过。。
例如:
. ├── __init__.py ├── crm │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ ├── views.py #from ..proj import settings ├── manage.py └── proj ├── __init__.py ├── settings.py #from .import urls ├── urls.py └── wsgi.py
views.py里代码
from ..proj import settings def sayhi(): print('hello world!') print(settings.DATABASES)
执行结果报错了
Traceback (most recent call last): File "my_proj/crm/views.py", line 4, in <module> from ..proj import settings SystemError: Parent module '' not loaded, cannot perform relative import
还可能出现的是这种
Traceback (most recent call last): File "my_proj/crm/views.py", line 4, in <module> from ..proj import settings SystemError: Parent module '' not loaded, cannot perform relative import
其实这两个错误的原因归根结底是一样的:在涉及到相对导入时,package所对应的文件夹必须正确的被python解释器视作package,而不是普通文件夹。否则由于不被视作package,无法利用package之间的嵌套关系实现python中包的相对导入。
文件夹被python解释器视作package需要满足两个条件:
- 文件夹中必须有__init__.py文件,该文件可以为空,但必须存在该文件。
- 不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口)。
所以这个问题的解决办法就是,既然你在views.py里执行了相对导入,那就不要把views.py当作入口程序,可以通过上一级的manage.py调用views.py
. ├── __init__.py ├── crm │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ ├── views.py #from ..proj import settings ├── manage.py #from crm import views └── proj ├── __init__.py ├── settings.py #from .import urls ├── urls.py └── wsgi.py
事实证明还是不行,报错
ValueError: attempted relative import beyond top-level package
但把from ..proj import settings
改成from . import models
后却执行成功了
from .. import models
会报错的原因是,这句代码会把manage.py所在的这一层视作package,但实际上它不是,因为package不能是顶层入口代码,若想不出错,只能把manage.py往上再移一层。
正确的代码目录结构如下
packages/ ├── __init__.py ├── manage.py #from my_proj.crm import views └── my_proj ├── crm │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ ├── views.py #from . import models; from ..proj import settings └── proj ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
注:虽然python支持相对导入,但对模块间的路径关系要求比较严格,处理不当就容易出错,so并不建议在项目里经常使用。
在Python中,与时间处理有关的模块就包括:time,datetime,calendar(很少用,不讲)。
一、在Python中,通常有这几种方式来表示时间:
- 时间戳
- 格式化的时间字符串
- 元组(struct_time)共九个元素。由于Python的time模块实现主要调用C库,所以各个平台可能有所不同
二、定义
UTC(Coordinated Universal Time,世界协调时)亦即格林威治天文时间,世界标准时间。在中国为UTC+8。DST(Daylight Saving Time)即夏令时。
时间戳(timestamp)的方式:通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
元组(struct_time)方式:struct_time元组共有9个元素,返回struct_time的函数主要有gmtime(),localtime(),strptime()。下面列出这种方式元组中的几个元素:
索引(Index) 属性(Attribute) 值(Values) 0 tm_year(年) 比如2011 1 tm_mon(月) 1 - 12 2 tm_mday(日) 1 - 31 3 tm_hour(时) 0 - 23 4 tm_min(分) 0 - 59 5 tm_sec(秒) 0 - 61 6 tm_wday(weekday) 0 - 6(0表示周日) 7 tm_yday(一年中的第几天) 1 - 366 8 tm_isdst(是否是夏令时) 默认为-1
time模块的方法
- time.localtime([secs]):将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
- time.gmtime([secs]):和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
- time.time():返回当前时间的时间戳。
- time.mktime(t):将一个struct_time转化为时间戳。
- time.sleep(secs):线程推迟指定的时间运行。单位为秒。
- time.asctime([t]):把一个表示时间的元组或者struct_time表示为这种形式:'Sun Oct 1 12:04:38 2017'。如果没有参数,将会将time.localtime()作为参数传入。
- time.ctime([secs]):把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
-
time.strftime(format[, t]):把一个代表时间的元组或者struct_time(如由time.localtime()和time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。
- 举例:time.strftime("%Y-%m-%d %X", time.localtime()) #输出'2017-10-01 12:14:23'
-
time.strptime(string[, format]):把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
- 举例:time.strptime('2017-10-3 17:54',"%Y-%m-%d %H:%M") #输出 time.struct_time(tm_year=2017, tm_mon=10, tm_mday=3, tm_hour=17, tm_min=54, tm_sec=0, tm_wday=1, tm_yday=276, tm_isdst=-1)
字符串转时间格式对应表 |
---|
Meaning | Notes | |
---|---|---|
%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. |
最后为了容易记住转换关系,看下图
datetime模块
相比time 模块,datetime模块的接口更直观、更容易调用
datetime.data:表示日期的类。常用的属性有year,month,day;
datetinme:表示的时间类。常用的属性有hour,minute,second,microsecond;
datetime.datatime:表示日期时间。
datetime.datadelta:表示时间间隔,即两个时间点之间的长度。
datetime.tzinfo;与时区有关的相关信息。
我们需要记住的方法仅以下几个:
d=datetime.datetime.now()返回当前的datetime日期类型
d.timestamp(),d.today(),d.year,d.timetuple()等方法可以调用
2.datetime.date.fromtimestamp(322222)把一个时间戳转换为datetime日期类型
3.时间运算
>>> datetime.datetime.now() datetime.datetime(2017, 10, 1, 12, 53, 11, 821218) >>> datetime.datetime.now() + datetime.timedelta(4) #当前时间 +4天 datetime.datetime(2017, 10, 5, 12, 53, 35, 276589) >>> datetime.datetime.now() + datetime.timedelta(hours=4) #当前时间+4小时 datetime.datetime(2017, 10, 1, 16, 53, 42, 876275)
4.时间替换
>>> d.replace(year=2999,month=11,day=30)
datetime.date(2999, 11, 30)
程序中很多地方需要用到随机字符,比如登陆网站的随机验证码,通过random模块可以很容易生成随机字符串
>>>random.randrange(1,10)#返回1-10之间的一个随机数,不包括10 >>>random.randint(1,10)#返回1-10之间的一个随机数,包括10 >>>random.randrange(0,100,2)#随机选取0到100间的偶数 >>>random.random.choice('abce3#$@1')#返回一个给定数据集合中的随机字符 '#' >>>random.sample('abcdefghij',3)#从多个字符中选取特定数量的字符 ['a','d'.'b'] #生成随机字符串 >>>import string >>>''.jion(random.sample(string.ascii_ascii_lowercase+string.digits,6)) '4fvdal' #洗牌 >>>a [0,1,2,3,4,5,6,7,8,9] >>>random.shuffle(a) >>>a [3,0,7,2,1,6,5,8,9,4]
os模块提供了很多允许你的程序与操作系统直接交互的功能
得到当前工作目录,即当前Python脚本工作的目录路径:os.getcwd() 返回指定目录下的所有文件和目录名:os.listdir() 函数用来删除一个文件;os.remove
删除多个目录:os.removedirs(r“c:python”) 检验给出的路径是否是一个文件:os.path.isfile() 检验给出的路径是否是一个目录:os.path.isdir() 判断是否是绝对路径:os.path.isabs() 检验给出的路径是否真地存:os.path.exists() 返回一个路径的目录名和文件名:os.path.split() e.g os.path.split('/home/swaroop/byte/code/poem.txt') 结果:('/home/swaroop/byte/code', 'poem.txt') 分离扩展名:os.path.splitext() e.g os.path.splitext('/usr/local/test.py') 结果:('/usr/local/test', '.py') 获取路径名:os.path.dirname() 获得绝对路径: os.path.abspath() 获取文件名:os.path.basename() 运行shell命令: os.system() 读取操作系统环境变量HOME的值:os.getenv("HOME") 返回操作系统所有的环境变量: os.environ 设置系统环境变量,仅程序运行时有效:os.environ.setdefault('HOME','/home/alex') 给出当前平台使用的行终止符:os.linesep Windows使用' ',Linux and MAC使用' ' 指示你正在使用的平台:os.name 对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix' 重命名:os.rename(old, new) 创建多级目录:os.makedirs(r“c:python est”) 创建单个目录:os.mkdir(“test”) 获取文件属性:os.stat(file) 修改文件权限与时间戳:os.chmod(file) 获取文件大小:os.path.getsize(filename) 结合目录名与文件名:os.path.join(dir,filename) 改变工作目录到dirname: os.chdir(dirname) 获取当前终端的大小: os.get_terminal_size() 杀死进程: os.kill(10884,signal.SIGKILL)