python模块介绍和引入

时间:2021-11-03 00:19:51

定义

在Python中,一个.py文件就称之为一个模块(Module)。

优点

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

2.编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。

3.使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中

模块建立

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

' a test module '

__author__ = 'Michael Liao'

import sys

def test():
    args = sys.argv
    if len(args)==1:
        print('Hello, world!')
    elif len(args)==2:
        print('Hello, %s!' % args[1])
    else:
        print('Too many arguments!')

if __name__=='__main__':
    test()

以上就是Python模块的标准文件模板

第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行

第2行注释表示.py文件本身使用标准UTF-8编码;

第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;

第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;

当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。

作用域

==模块定义的函数和变量==

1.正常的函数和变量名是公开的(public),可以被直接引用,比如:abcx123PI等;

2.类似_xxx__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc__abc等;

3.类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的__author____name__就是特殊变量,hello模块定义的文档注释也可以用特殊变量__doc__访问,我们自己的变量一般不要用这种变量名;

外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。

模块的搜索路径

#Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块
sys.path
['', 'D:\\Program Files\\Python37\\python37.zip', 'D:\\Program Files\\Python37\\DLLs', 'D:\\Program Files\\Python37\\lib', 'D:\\Program Files\\Python37', 'D:\\Program Files\\Python37\\lib\\site-packages']

添加自己的搜索目录

一是直接修改sys.path,添加要搜索的目录:

>>> import sys
>>> sys.path.append('/Users/michael/my_py_scripts')

这种方法是在运行时修改,运行结束后失效。

第二种方法是设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。

模块引入

两种方式

==1.import module_name==

调用模块的时候,已经解释了引入的全部代码

进行调用函数或变量,需要使用module_name.func/var

==2.from modeule_name import func/var==

只调用模块的函数和变量

进行调用函数或变量,直接使用func/var

软件目录结构

为什么要设计好目录结构?

"项目目录结构"其实也是属于"可读性和可维护性"的范畴,我们设计一个层次清晰的目录结构,就是为了达到以下两点:

  1. 可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目。
  2. 可维护性高: 定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好。

所以,我认为,保持一个层次清晰的目录结构是有必要的。更何况组织一个良好的工程目录,其实是一件很简单的事儿。

目录组织方式

关于如何组织一个较好的Python工程目录结构,已经有一些得到了共识的目录结构。在*的这个问题上,能看到大家对Python目录结构的讨论。

这里面说的已经很好了,我也不打算重新造*列举各种不同的方式,这里面我说一下我的理解和体会。

假设你的项目名为foo, 我比较建议的最方便快捷目录结构这样就足够了:

Foo/
|-- bin/
|   |-- foo
|
|-- foo/
|   |-- tests/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py
|   |-- main.py
|
|-- docs/
|   |-- conf.py
|   |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README

简要解释一下:

  1. bin/: 存放项目的一些可执行文件,当然你可以起名script/之类的也行。
  2. foo/: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/存放单元测试代码; (3) 程序的入口最好命名为main.py
  3. docs/: 存放一些文档。
  4. setup.py: 安装、部署、打包的脚本。
  5. requirements.txt: 存放软件依赖的外部Python包列表。
  6. README: 项目说明文件。

除此之外,有一些方案给出了更加多的内容。比如LICENSE.txt,ChangeLog.txt文件等,我没有列在这里,因为这些东西主要是项目开源的时候需要用到。如果你想写一个开源软件,目录该如何组织,可以参考这篇文章

下面,再简单讲一下我对这些目录的理解和个人要求吧。

关于README的内容

这个我觉得是每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。

它需要说明以下几个事项:

  1. 软件定位,软件的基本功能。
  2. 运行代码的方法: 安装环境、启动命令等。
  3. 简要的使用说明。
  4. 代码目录结构说明,更详细点可以说明软件的基本原理。
  5. 常见问题说明。

我觉得有以上几点是比较好的一个README。在软件开发初期,由于开发过程中以上内容可能不明确或者发生变化,并不是一定要在一开始就将所有信息都补全。但是在项目完结的时候,是需要撰写这样的一个文档的。

可以参考Redis源码中Readme的写法,这里面简洁但是清晰的描述了Redis功能和源码结构。

关于requirements.txt和setup.py

setup.py

一般来说,用setup.py来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情。这种方式普遍应用于开源项目中。不过这里的核心思想不是用标准化的工具来解决这些问题,而是说,一个项目一定要有一个安装部署工具,能快速便捷的在一台新机器上将环境装好、代码部署好和将程序运行起来。

这个我是踩过坑的。

我刚开始接触Python写项目的时候,安装环境、部署代码、运行程序这个过程全是手动完成,遇到过以下问题:

  1. 安装环境时经常忘了最近又添加了一个新的Python包,结果一到线上运行,程序就出错了。
  2. Python包的版本依赖问题,有时候我们程序中使用的是一个版本的Python包,但是官方的已经是最新的包了,通过手动安装就可能装错了。
  3. 如果依赖的包很多的话,一个一个安装这些依赖是很费时的事情。
  4. 新同学开始写项目的时候,将程序跑起来非常麻烦,因为可能经常忘了要怎么安装各种依赖。

setup.py可以将这些事情自动化起来,提高效率、减少出错的概率。"复杂的东西自动化,能自动化的东西一定要自动化。"是一个非常好的习惯。

setuptools的文档比较庞大,刚接触的话,可能不太好找到切入点。学习技术的方式就是看他人是怎么用的,可以参考一下Python的一个Web框架,flask是如何写的: setup.py

当然,简单点自己写个安装脚本(deploy.sh)替代setup.py也未尝不可。

requirements.txt

这个文件存在的目的是:

  1. 方便开发者维护软件的包依赖。将开发过程中新增的包添加进这个列表中,避免在setup.py安装依赖时漏掉软件包。
  2. 方便读者明确项目使用了哪些Python包。

这个文件的格式是每一行包含一个包依赖的说明,通常是flask>=0.10这种格式,要求是这个格式能被pip识别,这样就可以简单的通过 pip install -r requirements.txt来把所有Python包依赖都装好了。具体格式说明: 点这里

关于配置文件的使用方法

注意,在上面的目录结构中,没有将conf.py放在源码目录下,而是放在docs/目录下。

很多项目对配置文件的使用做法是:

  1. 配置文件写在一个或多个python文件中,比如此处的conf.py。
  2. 项目中哪个模块用到这个配置文件就直接通过import conf这种形式来在代码中使用配置。

这种做法我不太赞同:

  1. 这让单元测试变得困难(因为模块内部依赖了外部配置)
  2. 另一方面配置文件作为用户控制程序的接口,应当可以由用户*指定该文件的路径。
  3. 程序组件可复用性太差,因为这种贯穿所有模块的代码硬编码方式,使得大部分模块都依赖conf.py这个文件。

所以,我认为配置的使用,更好的方式是,

  1. 模块的配置都是可以灵活配置的,不受外部配置文件的影响。
  2. 程序的配置也是可以灵活控制的。

能够佐证这个思想的是,用过nginx和mysql的同学都知道,nginx、mysql这些程序都可以*的指定用户配置。

所以,不应当在代码中直接import conf来使用配置文件。上面目录结构中的conf.py,是给出的一个配置样例,不是在写死在程序中直接引用的配置文件。可以通过给main.py启动参数指定配置路径的方式来让程序读取配置内容。当然,这里的conf.py你可以换个类似的名字,比如settings.py。或者你也可以使用其他格式的内容来编写配置文件,比如settings.yaml之类的。

常用内建模块

time

python模块介绍和引入

获取struct_time对象

'''
time.localtime([secs])
与 gmtime() 相似但转换为当地时间。如果未提供 secs 或为 None ,则使用由 time() 返回的当前时间。当 DST 适用于给定时间时,dst标志设置为 1 。
'''
print(time.localtime()) #返回本地时间 的struct time对象格式

'''
time.gmtime([secs])
将 seconds since the epoch 为单位的时间转换为UTC的 struct_time ,其中dst标志始终为零。如果未提供 secs 或为 None ,则使用由 time() 返回的当前时间。忽略一秒的分数。
'''
print(time.gmtime()) #返回 UTC 0 的struc时间对象格式
print(time.gmtime(time.time()-800000)) #返回utc -6时间的struc时间对象格式

获取utc时差

print(time.clock()) #返回处理器时间,3.3开始已废弃 , 改成了time.process_time()测量处理器运算时间,不包括sleep时间,不稳定,mac上测不出来
print(time.altzone)  #返回与utc时间的时间差,以秒计算\

struct_time对象转换为标准字符串

import time
'''
time.asctime([t])
转换一个元组或 struct_time 表示的时间,由 gmtime() 或 localtime() 返回为以下形式的字符串: 'Sun Jun 20 23:21:05 1993' 。如果未提供 t ,则使用由 localtime() 返回的当前时间。 
'''
print(time.asctime()) 

'''
time.ctime([secs])
将自 seconds since the epoch 表示的时间转换为表示本地时间的字符串。如果未提供 secs 或为 None,则使用由 time() 返回的当前时间。 ctime(secs) 相当于 asctime(localtime(secs)) 。区域信息不被 ctime() 使用。
'''
print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上

struct_time和时间戳转换

#将utc时间戳转换成struct_time格式
print(time.gmtime(time.time()-86640)) 

#将struct时间对象转成时间戳
struct_2_stamp = time.mktime(string_2_struct) 
print(struct_2_stamp)

struct_time和自定义字符串格式转换

#将 日期字符串 转成 struct时间对象格式
string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") 
print(string_2_struct)

#将utc struct_time格式转成指定的字符串格式
print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) 

datetime

python模块介绍和引入

创建datetime对象

'''
classmethod datetime.now(tz=None)
Return the current local date and time.
'''
#获取本地的当前日期和时间
>>> from datetime import datetime
>>> datetime.now()
datetime.datetime(2019, 5, 22, 0, 11, 37, 450776)
>>> now = datetime.now()
>>> print (now)
2019-05-22 00:11:47.977408
        
'''
classmethod datetime.utcnow()
Return the current UTC date and time, with tzinfo None. This is like now(), but returns the current UTC date and time, as a naive datetime object.
'''
#获取UTC的当前日期和时间
>>> from datetime import datetime
>>> datetime.utcnow()
        
#获取指定日期和时间
>>> from datetime import datetime
>>> dt = datetime(2015, 4, 19, 12, 20) # 用指定日期时间创建datetime
>>> print(dt)
2015-04-19 12:20:00

datetime和timestamp转换

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

#datetime转换为timestamp
>>> from datetime import datetime
>>> now = datetime.now()
>>> now.timestamp()
1558455107.977408
#timestamp转换为datetime
>>> from datetime import datetime
>>> t = 1558455107.977408
>>> datetime.fromtimestamp(t)  #以UTC +8时区
datetime.datetime(2019, 5, 22, 0, 11, 47, 977408)
>>> print(datetime.utcfromtimestamp(t)) #以UTC 0 时区
2019-05-21 16:11:47.977408

str和datetime转换

#str转换为datetime
>>> from datetime import datetime
>>> cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
>>> print(cday)
2015-06-01 18:19:59
#datetime转换为str
>>> from datetime import datetime
>>> now = datetime.now()
>>> print(now.strftime('%a, %b %d %H:%M'))
Mon, May 05 16:28

时间加减

import datetime

print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
print(datetime.date.fromtimestamp(time.time()) )  # 时间戳直接转成日期格式 2016-08-19
print(datetime.datetime.now() )
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)) #时间替换

random

randrange()

'''
random.randrange(stop)
random.randrange(start, stop[, step])
从 range(start, stop, step) 返回一个随机选择的元素。 这相当于 choice(range(start, stop, step)) ,但实际上并没有构建一个 range 对象。
'''
>>> import random
>>> random.randrange(1,10,2)
3

random()

'''
random.random()
返回 [0.0, 1.0) 范围内的下一个随机浮点数。
'''
>>> random.random()
0.9237662880505335

os

提供给操作系统调用的接口

import 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    输出用于分割文件路径的字符串
os.name    输出字符串指示当前使用平台。win``-``>``'nt'``; Linux``-``>``'posix'
os.system(``"bash command"``)  运行shell命令,直接显示
os.environ  获取系统环境变量
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所指向的文件或者目录的最后修改时间

sys

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

json

支持所有语言

import json
data = {
    "name": "Tom",
    "age": 22
}
str_data = json.dumps(data)
print(type(str_data))
print(str_data)

data1 = json.loads(str_data)
print(type(data1))
print(data1)

with open("1.txt", "w") as fp:
    json.dump(data, fp)

with open("1.txt", "r") as fp:
    json_data = json.load(fp)
    print(type(json_data))
    print(json_data)

pickle

支持python

import  pickle
data = {
    "name": "Tom",
    "age": 22
}

str_data = pickle.dumps(data)
print(str_data, type(str_data))

data1 = pickle.loads(str_data)
print(data1, type(data1))

with open("2.txt", "wb") as fp:
    pickle.dump(data, fp)

with open("2.txt", "rb") as fp:
    data2 = pickle.load(fp)
    print(data2, type(data2))

shutil

shelve

将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式

import shelve
data = {
    "name": "Tom",
    "age": 22
}
fp = shelve.open("3.txt")
fp["name"] = "Tom"
fp["age"] = 22
fp["data"] = data

for i, j in fp.items():
    print(i, j)

fp["age"] = 25

for i, j in fp.items():
    print(i, j)

fp.close()

xml

pyyaml

configparser

hashlib

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

import hashlib

m = hashlib.md5()
m.update(b"123")
print("m.digest():", m.digest())
print("m.hexdigest()", m.hexdigest())
print(len(m.digest())) #2进制格式hash
print(len(m.hexdigest())) #16进制格式hash
m.update(b"456")
print("m.digest():", m.digest())
print("m.hexdigest()", m.hexdigest())
print(len(m.digest())) #2进制格式hash
print(len(m.hexdigest())) #16进制格式hash

m1 = hashlib.md5()
m1.update(b"123456")
print("m1.digest():", m1.digest())
print("m1.hexdigest()", m1.hexdigest())
print(len(m1.digest())) #2进制格式hash
print(len(m1.hexdigest())) #16进制格式hash

#输出结果
m.digest(): b'\xe1\n\xdc9I\xbaY\xab\xbeV\xe0W\xf2\x0f\x88>'
m.hexdigest() e10adc3949ba59abbe56e057f20f883e
16
32
m1.digest(): b'\xe1\n\xdc9I\xbaY\xab\xbeV\xe0W\xf2\x0f\x88>'
m1.hexdigest() e10adc3949ba59abbe56e057f20f883e
16
32

import hashlib

# ######## md5 ########

hash = hashlib.md5()
hash.update(b'admin')
print(hash.hexdigest())

# ######## sha1 ########

hash = hashlib.sha1()
hash.update(b'admin')
print(hash.hexdigest())

# ######## sha256 ########

hash = hashlib.sha256()
hash.update(b'admin')
print(hash.hexdigest())

# ######## sha384 ########

hash = hashlib.sha384()
hash.update(b'admin')
print(hash.hexdigest())

# ######## sha512 ########

hash = hashlib.sha512()
hash.update(b'admin')
print(hash.hexdigest())

hmac

基于密钥的消息验证

如果salt是我们自己随机生成的,通常我们计算MD5时采用md5(message + salt)。但实际上,把salt看做一个“口令”,加salt的哈希就是:计算一段message的哈希时,根据不通口令计算出不同的哈希。要验证哈希值,必须同时提供正确的口令。

这实际上就是Hmac算法:Keyed-Hashing for Message Authentication。

'''
hmac.new(key, msg=None, digestmod=None)
Return a new hmac object. key is a bytes or bytearray object giving the secret key. If msg is present, the method call update(msg) is made. digestmod is the digest name, digest constructor or module for the HMAC object to use.
'''
import hmac
h = hmac.new(b'123', b'456')
print (h.hexdigest())

logging

re

常用正则表达式

'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'     匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*'     匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac")  结果为['abb', 'ab', 'a']
'+'     匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?'     匹配前一个字符1次或0次
'{m}'   匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|'     匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
 
 
'\A'    只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z'    匹配字符结尾,同$
'\d'    匹配数字0-9
'\D'    匹配非数字
'\w'    匹配[A-Za-z0-9]
'\W'    匹配非[A-Za-z0-9]
's'     匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
 
#r在正则表达式前面不需要考虑转义
s = r'ABC\-001' # Python的字符串
# 对应的正则表达式字符串不变:
# 'ABC\-001'

#分组匹配
>>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
>>> m
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>
>>> m.group(0)
'010-12345'
>>> m.group(1)
'010'
>>> m.group(2)
'12345'
>>> m.groups()
('010', '12345')

#贪婪匹配
#正则默认是贪婪匹配,尽可能多的匹配数字
>>> re.match(r'^(\d+)(0*)$', '102300').groups()
('102300', '')
#由于\d+采用贪婪匹配,直接把后面的0全部匹配了,结果0*只能匹配空字符串了。
#必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:
>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
('1023', '00')

#编译
#当我们在Python中使用正则表达式时,re模块内部会干两件事情:
#编译正则表达式,如果正则表达式的字符串本身不合法,会报错;
#用编译后的正则表达式去匹配字符串。
#如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配:
    
>>> import re
# 编译:
>>> re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
# 使用:
>>> re_telephone.match('010-12345').groups()
('010', '12345')
>>> re_telephone.match('010-8086').groups()
('010', '8086')

常用的匹配语法

re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符当做列表分隔符
re.sub      匹配字符并替换