第六章:Python基础の反射与常用模块解密

本课主题

  • 反射 Mapping 介绍和操作实战
  • 模块介绍和操作实战
  • random 模块
  • time 和 datetime 模块
  • logging 模块
  • sys 模块
  • os 模块
  • hashlib 模块
  • re 模块
  • 本周作业

反射 Mapping 介绍和操作实战

反射是利用字符串的形式去对象 (模块) 中操作 (寻找/检查/删除/设置) 成员,以後看其他源碼的時候會經常看到反射,最有代表性的就是 Tornado 和 Django 框架

案例例子

假设创建了一个common.py,程序里有3个功能,比如网站里的登录页面、主页页面和登出页面都是不同的页面,要显示的内容都不一样。

def login():
print("Login Page") def logout():
print("Logout Page") def home():
print("HomePage")

common.py

再创建一个py程序:index.py,程序一般是写一个判断然后会基于调用不同的功能返回不同的结果(参考调用方法一的代码)。

import common

#根据用户不同的输入而返回不同的信息
def run():
inp = input("请输入要访问的 url: ")
if inp == "login": # 当用户输入 login,还看到 login 页面
common.login()
elif inp == "logout": # 当用户输入 logout,还看到 logout 页​​面
common.logout()
elif inp == "home": # 当用户输入 home,还看到 home 页面
common.home()
else:
print("") if __name__ == "__main__":
run()

index.py 调用方法一

这个时候,就可以运用反射的方法(参考调用方法二的代码),直接基于用户输入,返回需要執行的功能,这样就可以减少判断逻辑代码需要的时间。

# 利用字符串的形式去对象 (模块) 中操作 (寻找/检查) 成员

import common

def run():
inp = input("请输入要访问的 url: ")
is_exists = hasattr(common,inp) # 检查用户输入是否在common模块里存在的一个成员
if is_exists:
func = getattr(common, inp) # 到common模块寻找用户输入的一个成员
func()
else:
print("") if __name__ == "__main__":
run()

index.py 调用方法二

运用 hasattr( ) 、 getattr( )、delattr( )、setattr( ) 函数来实现,這几個反射函数分別接收兩個参数(参数一可以是模块, 参数二是参数一的成員 - 它接受一个字符串类型的成员名称),比如说:如果 common 模块里有 login( ) 函数,在调用反射时,基本代码语法是 hasattr(s2,"login")

#s2.py
def login():
print("login....") #s1.py
import s2 if hasattr(s2,"login"):
func = getattr(s2, "login") #接受字符串类型的成员名称
func() """
login....
"""

反射基本代码语法

hasattr(参数一,参数二) # 到模块里检查成员
#参数一可以是模块, 参数二是参数一的成员
getattr(参数一,参数二) # 到模块里寻找成员
#参数一可以是模块, 参数二是参数一的成员
delattr(参数一,参数二) # 到模块裡把這個成員删掉
#参数一可以是模块, 参数二是参数一的成员
setattr(参数一,参数二) # 到模块裡再设置一個成員
#参数一可以是模块, 参数二是参数一的成员

在这里我们需要了解一下导入模块的方法,有以下两個方法:

  1. 第一是 import package_name / import package_name as alias_name
    import common
    import common as obj obj.f1( )

    import "package_name"

  2. 第二是 obj = __import__("package_name"),然后基于对象名称去调用它的方法,可以通过字符串的形式导入模块。
    obj = __import__("common")
    obj.f1( )

    __import__( )方式一

    这里调用的__import__(“common”),默认只能导入第一层的模块,也就是说如果你需要传入lib.account.xxxxx的话,此时你需要加入一个参数,意思说你写入的路径是什么我就导入什么。

    obj = __import__("lib. " + m, fromlist = True)
    obj.f1( )

    __import__( )方式二

    你可以调用 split( ) 方法把模块的路径进行分割,然后传入__import__(m),这样你就可以把正确的模块导入到程序里。

    >>> inp = "account/login"
    >>> inp.split("/")
    ['account', 'login'] >>> m,f = inp.split("/") >>> m
    'account' >>> f
    'login'

    split("/")

    def run():
    inp = input("请输入要访问的 url: ")
    m,f = inp.split("/")
    obj = __import__(m) if hasattr(obj,f):
    func = getattr(obj, f)
    func()
    else:
    print("") if __name__ == "__main__":
    run() """
    account/login
    >> Login Page...
    """

    index.py 调用方法三

模块介绍和操作实战

random 模块

random( ) 函数是用来随机生成数字

fruits = ['apple','banana','orange','coconuts','straweberry','lemon','kumquat','blueberry','melon']
random.randint(1,10) #随机获取1到10的数字
>>> 10
random.randrange(1,10) #随机获取1到10的数字
>>> 5
random.sample(fruits, k=5) #从集合中随机获取k个元素
>>> ['orange', 'apple', 'blueberry', 'banana', 'lemon']
random.choice(fruits) #从集合中随机获取其中一个元素
>>> 'orange'
random.shuffle(fruits) #把集合中的元素打乱
#['straweberry', 'apple', 'melon', 'blueberry', 'orange', 'lemon', 'kumquat', 'banana', 'coconuts']

random 常用函数

import random

word_list = []
for i in range(6):
random_num = random.randrange(0, 5)
if random_num == 2 or random_num == 4:
num = random.randrange(0, 10)
word_list.append(str(num))
else:
temp = random.randrange(65, 91)
word = chr(temp) # 把数字变字母
word_list.append(word) words = "".join(word_list)
print(words) """
F69Y2G
"""

random( )函数

time 模块

0   tm_year     年
1 tm_mon 月
2 tm_mday 日
3 tm_hour 时
4 tm_min 分
5 tm_sec 秒
6 tm_wday 一周中的第几天
7 tm_yday 一年中的第几天
8 tm_isdst 夏令时

时间元组各项含义

  1. 从1970年1月1号12:00am 开始计算的一个时间戳 Unix timestamp
    import time
    
    >>> print(time.time())
    1473427097.89171

    time.time()

  2. 返回当前系统时间转换成 字符串类型
    import time
    
    >>> print(time.ctime())
    Fri Sep 9 21:28:13 2016 >>> print(time.ctime(time.time()-86400))
    Thu Sep 8 21:29:06 2016

    time.ctime( )

  3. 返回当前系统时间转换成 struct_time类型
    >>> import time
    
    >>> time_obj = time.gmtime() 
    
    >>> print(time_obj)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=9, tm_hour=13, tm_min=29, tm_sec=41, tm_wday=4, tm_yday=253, tm_isdst=0) >>> print(time_obj.tm_year,time_obj.tm_mon)
    2016 9 >>> type(time_obj)
    <class 'time.struct_time'> >>> ret = "Year={year} Month={mnth}".format(year=time_obj.tm_year,mnth=time_obj.tm_mon) >>> print(ret)
    Year=2016 Month=9 >>> time_pre_obj = time.gmtime(time.time()-86400) # 返回struct_time类型
    >>> print(time_pre_obj)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=8, tm_hour=13, tm_min=34, tm_sec=49, tm_wday=3, tm_yday=252, tm_isdst=0)

    time.gmtime( )

  4. 按本地时间来显示时间,并且返回 struct_time类型
    >>> print(time.localtime())
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=9, tm_hour=21, tm_min=38, tm_sec=47, tm_wday=4, tm_yday=253, tm_isdst=0) >>> time_obj = time.localtime() >>> print(time_obj)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=9, tm_hour=21, tm_min=38, tm_sec=59, tm_wday=4, tm_yday=253, tm_isdst=0) >>> type(time_obj)
    <class 'time.struct_time'>

    time.localtime( )

  5. 把一个struct_time类型转换成时间戳
    >>> print(time.mktime(time_obj))
    1473428339.0

    time.mktime( )

  6. 让时间睡眠
    >>> time.sleep(4)
    >>> print("--------")

    time.sleep( )

  7. 將 struct_time 类型转换成字符串类型 (from struct_time to string)
    >>> print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()))
    2016-09-09 13:47:50 >>> print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
    2016-09-09 21:47:51

    time.strftime( )

  8. 將字符串类型转换成 struct_time 类型 (from string to struct_time)
    >>> tm = time.strptime("2016-09-03","%Y-%m-%d")  # 將字符串类型转换成struct_time类型
    
    >>> print(tm)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=3, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=247, tm_isdst=-1) >>> type(tm)
    <class 'time.struct_time'> >>> print(time.mktime(tm))
    1472832000.0

    time.strptime( )

Datetime 模块

  1. 输出:2016-09-03
    >>> import datetime
    >>> d1 = datetime.date.today()
    >>> print(d1)

    datetime.date.today()

  2. 时间戳直接转成日期格式 2016-08-19
    >>> d2 = datetime.date.fromtimestamp(time.time());
    >>> print(d2)
    2016-09-09

    datetime.date.fromtimestamp()

  3. current time
    >>> current_time = datetime.datetime.now()
    >>> print(current_time)
    2016-09-09 21:59:45.125933

    datetime.datetime.now()

  4. 返回  struct_time 类型
    >>> t = current_time.timetuple()
    
    >>> print(t)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=9, tm_hour=21, tm_min=59, tm_sec=45, tm_wday=4, tm_yday=253, tm_isdst=-1) >>> type(t)
    <class 'time.struct_time'>

    timetuple( )

  5. 时间的加减在Python中会调用datetime.timedelta ( )
    >>> d3 = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    >>> print(d3)
    2016-09-09 22:03:29 >>> new_date = datetime.datetime.now() + datetime.timedelta(days=10)
    >>> print(new_date)
    2016-09-19 22:03:38.745696 >>> new_hour = datetime.datetime.now() + datetime.timedelta(hours=4)
    >>> print(new_hour)
    2016-09-10 02:03:41.642530 >>> new_hour = datetime.datetime.now() + datetime.timedelta(hours=4)
    >>> print(new_hour)
    2016-09-10 02:03:44.630359

    时间的加减

  6. datetime.datetime.strptime( )
    >>> tm = datetime.datetime.strptime("2016-09-03","%Y-%m-%d")
    >>> print(tm)
    2016-09-03 00:00:00

    strptime( )

  7. replace( )
    >>> current_time = datetime.datetime.now()
    >>> print(current_time)
    2016-09-09 22:07:10.352970 >>> replace_time = current_time.replace(2015,5)
    >>> print(replace_time)
    2015-05-09 22:07:10.352970 >>> print(type(current_time))
    <class 'datetime.datetime'> >>> print(type(replace_time))
    <class 'datetime.datetime'>

    replace( )

Date Format

格式    含义                        取值范围(格式)
%y 去掉世纪的年份                   00~99,如 ""
%Y 完整的年份                     如 ""
%j 指定日期是一年中的第几天              001~366
%m 返回月份                      01~12
%b 本地简化月份的名称                 简写英文月份
%B 本地完整月份的名称                 完整英文月份
%d 该月的第几日                    如5月1日返回 ""
%H 该日的第几时(24小时)                00~23
%l 该日的第几时(12小时)                01~12
%M 分种                        00~59
%S 秒                         00~59
%U 在该年中的第多少星期(以每周日为一周的起点) 00~53
%W 在该年中的第多少星期(以每周一为一周的起点) 00~53
%w 一星期中的第几天                  0~6
%Z 时区                        中国返回CST,即China Standard Time
%x 日期                        日/月/年
%X 时间                        时:分:秒
%c 详细日期时间                    日/月/年 时:分:秒
%% '%'字符                      '%'字符
%p 上下午                       AM or PM

format格式定义

logging 模块

logging 基础

每个程序都需要有日志记录,日志有几个级别:1. DEBUG; 2.INFO; 3. WARNING; 4.ERROR; 5.CRITICAL

import logging

logging.warning("User [alex] attempt wrong password for more than 3 times")
logging.critical("Server is down") logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too') #WARNING:root:User [alex] attempt wrong password for more than 3 times
#CRITICAL:root:Server is down
#WARNING:root:And this, too

logging

想输出日志到文件可以调用以下函数,filename: 文件名,filemode: 写入模式,level: 日志的级别 (跟这个级别同等或者是比这个更高级别的日志才会写入文件)

logging.basicConfig(filename='log.txt',filemode='w',level=logging.INFO)

把 basicConfig 加到程序中然后执行程序,因为日志级别是INFO,所以这里的结果是只有INFO级别或以上的,才会写入log.txt的文件里

import logging

logging.basicConfig(filename='log.txt',filemode='w',level=logging.INFO)

logging.warning("User [alex] attempt wrong password for more than 3 times")
logging.critical("Server is down")
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too') #log.txt 会有INFO级别或以上的日志
"""
WARNING:root:User [alex] attempt wrong password for more than 3 times
CRITICAL:root:Server is down
INFO:root:So should this
WARNING:root:And this, too
"""

Log写进文件的例子

basicConfig可以传入很多不同的参数

logging.basicConfig(filename='log.txt',
level=logging.DEBUG,
format='%(asctime)s %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p')
import logging

logging.basicConfig(filename='log.txt',
level=logging.DEBUG,
format='%(asctime)s %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p') logging.warning("User [alex] attempt wrong password for more than 3 times")
logging.critical("Server is down")
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too') # log.tx.
"""
09/09/2016 11:15:35 PM User [alex] attempt wrong password for more than 3 times
09/09/2016 11:15:35 PM Server is down
09/09/2016 11:15:35 PM This message should go to the log file
09/09/2016 11:15:35 PM So should this
09/09/2016 11:15:35 PM And this, too
"""

Log写进文件的例子二

logging 进阶

如果想打印日志到文件和 Console 上,必须先了解以下几个概念:

第六章:Python基础の反射与常用模块解密

  1. 第一步,创建 Logger,然后设置全区的日志级别。(会比较全区和区部的日志级别,较高的那个会成为该日志输出级别)
    logger = logging.getLogger('TEST-LOG')
    logger.setLevel(logging.INFO) #configure a global logging level

    logger

  2. 第二步、创建Console Handler 对象,也可以设置 Console 控制台的日志级别,不可以比全区的日志记录级别小,CRITICAL> ERROR> WARNING> INFO> DEBUG。也就是说这两个日志记录级别会比较然后选出最大的那个日志记录级别
    console_handler = logging.StreamHandler() #print the log on the console
    console_handler.setLevel(logging.DEBUG)

    console_handler

  3. 第三步、创建File Handler 对象,也可以设置 File Handler 的日志级别。
    file_handler = logging.FileHandler("access.log")
    file_handler.setLevel(logging.WARNING)

    file_handler

  4. 第四步、创建 Formatter,这是决定输出的格式
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(filename)s - %(levelname)s - %(message)s - %(lineno)s - %(process)d')

    formatter

  5. 第五步、把 Formatter 加到 console_handler 和 file_handler,各自可以有不同的输出格式
    console_handler.setFormatter(formatter)
    file_handler.setFormatter(formatter)

    setFormatter(formatter)

  6. 第六步、把 Handler 加到 console_handle 和 file_handler 对象里
    logger.addHandler(console_handler)
    logger.addHandler(file_handler)

    addHandler( )

把以上第1步 到 第6步加起來:

import logging

#create logger
logger = logging.getLogger('TEST-LOG')
logger.setLevel(logging.INFO) #configure a global logging level # create console handler and set the level to debug
console_handler = logging.StreamHandler() #print the log on the console
console_handler.setLevel(logging.DEBUG) #override the global logging configuration level and specifiy the configuration on the console # create file handler and set level to warning
file_handler = logging.FileHandler("access.log")
file_handler.setLevel(logging.WARNING) #override the global logging configuration level and specifiy the configuration on the file_system # create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(filename)s - %(levelname)s - %(message)s - %(lineno)s - %(process)d') # add formatter to ch and fh
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter) # add console_handler and ffile_handler to logger
# 把日志打印到指定的Handler里
logger.addHandler(console_handler)
logger.addHandler(file_handler) # 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message') # Console
"""
2016-09-09 23:26:25,907 - TEST-LOG - loggingOps_2.py - INFO - info message - 32 - 1168
2016-09-09 23:26:25,908 - TEST-LOG - loggingOps_2.py - WARNING - warn message - 33 - 1168
2016-09-09 23:26:25,909 - TEST-LOG - loggingOps_2.py - ERROR - error message - 34 - 1168
2016-09-09 23:26:25,910 - TEST-LOG - loggingOps_2.py - CRITICAL - critical message - 35 - 1168
""" # access.log
"""
2016-09-04 00:54:05,713 - TEST-LOG - loggingOps_2.py - WARNING - warn message - 33 - 4827
2016-09-04 00:54:05,714 - TEST-LOG - loggingOps_2.py - ERROR - error message - 34 - 4827
2016-09-04 00:54:05,714 - TEST-LOG - loggingOps_2.py - CRITICAL - critical message - 35 - 4827
2016-09-09 23:26:25,908 - TEST-LOG - loggingOps_2.py - WARNING - warn message - 33 - 1168
2016-09-09 23:26:25,909 - TEST-LOG - loggingOps_2.py - ERROR - error message - 34 - 1168
2016-09-09 23:26:25,910 - TEST-LOG - loggingOps_2.py - CRITICAL - critical message - 35 - 1168
"""

完整日志代码例子

logging 的参数

[更新中] 

sys 模块

import sys

for p in sys.path:
print(p)

sys.path

def view_bar(num,total):
rate = num / total
rate_num = int(rate * 100)
# r = "\r%d%%" % (rate_num,)
r1 = "\r%s>%d%%" % ("="*num, rate_num) # print(r)
sys.stdout.write(r1)
sys.stdout.flush() for i in range(0,101):
time.sleep(0.1)
view_bar(i,100) """
====================================================================================================>100%
"""

status_bar 进度条

os 模块

os.getcwd()                 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
os.makedirs('dir1/dir2') 可生成多层递归目录
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename("oldname","new") 重命名文件/目录
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所指向的文件或者目录的最后修改时间

os总览

设置文件夹的目录路径:

# ~/PycharmProjects/mysite/test.py
file = os.path.abspath(__file__) # 文件名称:~/PycharmProjects/mysite/test.py
dirname = os.path.dirname(file) # test.py 文件所在的文件夹:~/PycharmProjects/mysite/
basedir = os.path.dirname(dirname) # mysite 文件夹所在的文件夹:~/PycharmProjects/ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))以下 

以下是一个python 项目的结构树

web-spider			# 爬虫程序的根目录
|- data # 数据存在文件夹
|- crawler # 爬源数据的程序
|- trasformer       # 数据清理的程序
|- loader # 数据分发的程序
.env # 参数
config.py # 导入参数的程序

首先定义 .env 的参数

# .env
AWS_ACCESS_KEY_ID=JKSLNFJY639GHNO2
AWS_SECRET_ACCESS_KEY=1aVFk9lKMsc3ssfasfsfsafsfsNBKDhslafhks

然后在 config.py 中

hashlib 模块

  1. 首先创建一个MD5对象,然后把字节形式的字符串更新到MD5对象里,然后输出 MD5 值,
    obj1 = hashlib.md5()
    obj1.update(bytes('janice123', encoding='utf-8'))
    print(obj1.hexdigest())
  2. 如果担心 MD5 密码有给人撞码的机会,可以在创建MD5对象的时候,传入一个以字节形式的字符串,基于这个基础上才调用更新的方式,这样就比较安全。
    key = bytes('asdfghjhgfdsdfg', encoding='utf-8')
    obj1 = hashlib.md5(key)
import hashlib

key = bytes('asdfghjhgfdsdfg', encoding='utf-8')
pswd = bytes('admin', encoding='utf-8')
combined = bytes('asdfghjhgfdsdfgadmin', encoding='utf-8') # Add a key to the md5
obj1 = hashlib.md5(key) # 创建了一个有key的 md5 对象
obj1.update(pswd)
print("key:", obj1.hexdigest()) #12fffe3f1295037f8814f78fe063f290
print("key:",obj1.digest()) # # Original md5
obj2 = hashlib.md5() # 创建了一个 md5 对象
obj2.update(pswd)
print("pswd:", obj2.hexdigest()) #21232f297a57a5a743894a0e4a801fc3
print("pswd:",obj2.digest()) # # Combined Version
obj3 = hashlib.md5() # 创建了一个 md5 对象
obj3.update(combined)
print("combined:",obj3.hexdigest()) #12fffe3f1295037f8814f78fe063f290
print("combined:",obj3.digest()) # """
key: 12fffe3f1295037f8814f78fe063f290
key: b'\x12\xff\xfe?\x12\x95\x03\x7f\x88\x14\xf7\x8f\xe0c\xf2\x90' pswd: 21232f297a57a5a743894a0e4a801fc3
pswd: b'!#/)zW\xa5\xa7C\x89J\x0eJ\x80\x1f\xc3' combined: 12fffe3f1295037f8814f78fe063f290
combined: b'\x12\xff\xfe?\x12\x95\x03\x7f\x88\x14\xf7\x8f\xe0c\xf2\x90'
"""

完整的 md5( )加密例子

re 模块

\w 匹配字符
\W 匹配非字符
\s 匹配空白符、换行
\S 匹配非空白符、非换行
\d 匹配数字
\D 匹配非数字
\b 匹配单词的开始或结束
\B 匹配非单词的开始或结束

匹配数据的类型定义

\w{3} 匹配有3个字符串的字符
\w{,3} 匹配有1个或者2个或者3个字符串的字符
\w{3,} 匹配有3个或者无限大字符串的字符
\w{3,5} 匹配有3个或者4个或者5个字符串的字符
\w? 匹配0个或者有1个字符串的字符
\w* 匹配0个或者无限大字符串的字符
\w+ 匹配有1个或者无限大字符串的字符

匹配数据的数量定义

findall( )

re.findall(pattern,string)
#pattern: 匹配的条件 string: 需要匹配的字符串
  1. 这里是一个的findall( ) 的例子,findAll( ) 返回的是一个列表类型
    >>> import re
    >>> ret = re.findall('janice','wertyujkjgjanicedfuygihujksaf')
    >>> print(ret,type(ret))
    ['janice'] <class 'list'>

    findall( )例子

  2. 如果是有*的话,是代表所有字符,看看以下这个例子:意思是从参数二:需要匹配的字符串,找参数一的条件:jan开头,后面有一个字符,然后是任何的东西,最后必需是ce结尾
    >>> re.findall('jan.*ce','wertyujkjanjgdfuygceihujksaf')
    ['janjgdfuygce']

    findall( )有*例子

  3. 如果是有{ }的话,里面可以加入数字的函数来定义容许出现多少个字符,看看以下这个例子。从参数二:需要匹配的字符串,找参数一的条件:
    >>> re.findall('ja.{3}ce','wertjaabccesaf')
    ['jaabcce'] >>> re.findall('ja.{1,5}ce','wertjaabcdecesaf')
    ['jaabcdece'] >>> re.findall('ja.{1,5}ce','wertjaabcdfdffdecesaf')
    [] >>> re.findall('ja.{1,}ce','wertjaabcdfdffdecesaf')
    ['jaabcdfdffdece'] >>> re.findall('jan{,3}ice','python-jannnice-python')
    ['jannnice']

    findall( )有{}例子

  4. 如果是有[ ]的话,里面可以加入数字/字母的函数来定义容许出现多少个数字/字符,看看以下这个例子。从参数二:需要匹配的字符串,找参数一的条件:
    >>> re.findall('a[bc]d','abd')
    ['abd'] >>> re.findall('a[bc]d','acd')
    ['acd'] >>> re.findall('a[a-z]d','abbd')
    [] >>> re.findall('a[a-z]d','ajd')
    ['ajd']

    findall( )有[]例子

match( )

从头开始往后匹配,如果能匹配上的话,就不会再往下走,只取第一个可匹配的字符

re.match(pattern,string,flags=0)
#pattern: 匹配的条件 string: 需要匹配的字符串 flags:
  1. 如果用 match( )函数的話,它只會匹配從0開始的字符串,看下面的例子:用 match( ) 函数匹配成功时,返回的是一个 SRE_Match 的对象,如果想获取 match 的结果,必须调用SRE_Match里的 group() 函数
    # 用 match 函数匹配成功时,返回的是一个 SRE_Match 的对象
    >>> re.match("com","google.com")
    >>> re.match("com","comgoogle.com")
    <_sre.SRE_Match object; span=(0, 3), match='com'> #返回的是一个 SRE_Match 的对象
    >>> ret=re.match("com","comgoogle.com")
    >>> type(ret)
    <class '_sre.SRE_Match'> # 想要获取 match 的结果,必须调用SRE_Match里的 group() 函数
    >>> re.match("com","comgoogle.com").group()
    'com'

    match( )例子

serach( )

re.search(pattern,string,flags=0)
#pattern: 匹配的条件 string: 需要匹配的字符串 flags:
  1. 如果用 search( )函数的話,它會在需要匹配的字符串找第一個符合匹配条件的字符,看下面的例子:用 search( ) 函数匹配成功时,返回的是一个 SRE_Match 的对象,如果想获取 search 的结果,必须调用SRE_Match里的 group() 函数
    >>> re.search("com","google.com")
    <_sre.SRE_Match object; span=(7, 10), match='com'> >>> ret = re.search("com","google.com")
    >>> type(ret)
    <class '_sre.SRE_Match'> >>> ret.group()
    'com'

    search( )例子

sub( )

re.sub(pattern,repl,string,max=0)
#pattern: 匹配的条件;string: 需要匹配的字符串
  1. 替換功能,它返回的是字符串类型
    # 在字符串裡以 py 替换全有 python
    >>> ret = re.sub("python","py","python is good! python is fun! python is easy!")
    >>> ret
    'py is good! py is fun! py is easy!'
    >>> type(ret)
    <class 'str'> # 在字符串裡以 py 替换共2個 python
    >>> ret = re.sub("python","py","python is good! python is fun! python is easy!",2)
    >>> ret
    'py is good! py is fun! python is easy!'

    sub( )例子

split( )

>>> re.split("\d+","one1two2three3four4")
['one', 'two', 'three', 'four', ''] >>> re.split("\d","one1two2three3four4")
['one', 'two', 'three', 'four', ''] >>> re.split("\d+","one1two212three3four4")
['one', 'two', 'three', 'four', '']
>>> >>> re.split("\d","one1two212three3four4")
['one', 'two', '', '', 'three', 'four', '']

split( )

re.compile( )

re 的分组

去已经匹配到的数据中再提取数据

  1. match( )的分組例子
    import re
    origin = "has dfghjertyu45678"
    ret = re.match("h\w+",origin)
    ret1 = re.match("h(\w+)",origin)
    ret2 = re.match("h(?P<name>\w+)",origin) print(ret.group())
    print(ret1.groups())
    print(ret2.groupdict()) """
    has
    ('as',)
    {'name': 'as'}
    """

    match( ) 有分組例子

  2. search( )的分組例子
  3. findall( )的分組例子
    origin = "hasaabc dfjert halaabc yu45678"
    ret = re.findall("h\w+",origin)
    ret1 = re.findall("h(\w+)a(ab)c",origin)
    ret2 = re.findall("h(?P<name>\w+)",origin) print(ret)
    print(ret1)
    print(ret2) """
    ['hasaabc', 'halaabc']
    [('as', 'ab'), ('al', 'ab')]
    ['asaabc', 'alaabc']
    """

    findall( ) 有分組例子

  4. split( )的分組例子

到底这几个有什么分别,应该在什么情境用呢: * + ? {}

Love, Kenneth	kenneth@teamtreehouse.com	(555) 555-5555	Teacher, Treehouse	@kennethlove
McFarland, Dave dave@teamtreehouse.com (555) 555-5554 Teacher, Treehouse
Arthur, King king_arthur@camelot.co.uk King, Camelot
Österberg, Sven-Erik governor@norrbotten.co.se Governor, Norrbotten @sverik
, Tim tim@killerrabbit.com Enchanter, Killer Rabbit Cave
Carson, Ryan ryan@teamtreehouse.com (555) 555-5543 CEO, Treehouse @ryancarson
Doctor, The doctor+companion@tardis.co.uk Time Lord, Gallifrey
Exampleson, Example me@example.com 555-555-5552 Example, Example Co. @example
Obama, Barack president.44@us.gov 555 555-5551 President, United States of America @potus44
Chalkley, Andrew andrew@teamtreehouse.com (555) 555-5553 Teacher, Treehouse @chalkers
Vader, Darth darth-vader@empire.gov (555) 555-4444 Sith Lord, Galactic Empire @darthvader
Fernández de la Vega Sanz, María Teresa mtfvs@spain.gov First Deputy Prime Minister, Spanish Govt.

name.txt

import re

names_file = open("names.txt", encoding="utf-8")
data = names_file.read()
names_file.close() last_name = r'Love'
first_name = r'Kenneth'
print(re.match(last_name, data))
print(re.search(first_name, data))
print(re.findall(r'\(?\d{3}\)?-?\s?\d{3}-\d{4}',data))
print(re.findall(r'\w*, \w+',data))
print(re.findall(r'[-\w\d+.]+@[-\w\d.]+',data))
print(re.findall(r'\b[trehouse]{9}\b',data, re.I))

address_book.py

模块中的特殊变量

  1. __doc__ : 狻取文件的注释
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: Janice Cheng
    """
    我是注释
    """ import s2 print(__doc__) """
    我是注释
    """

    __doc__

  2. __file__: 当前 .py 文件所在的目录
    import sys
    import os print("__file__:",__file__) abs_path = os.path.abspath(__file__) # 获取某个py的绝对路径
    print("abs_path:",abs_path) p1 = os.path.dirname(abs_path)
    p2 = os.path.dirname(p1) sys.path.append(p2) print("p1:",p1)
    print("p2:",p2) """ __file__: /Users/janice/PycharmProjects/s13/day6/bin/admin.py
    abs_path: /Users/janice/PycharmProjects/s13/day6/bin/admin.py
    p1: /Users/janice/PycharmProjects/s13/day6/bin
    p2: /Users/janice/PycharmProjects/s13/day6 """

    __file__

  3. __package__: 说明当前 py 文件在哪个包里
  4. __name__: 代表当前文件的文件名称。假设我在 s1.py 文件里执行程序的话,当前 s1.py 的 __name__ 就会等于 __main__。也就是说只有你执行主文件的情况下,你的功能才会被执行,它不容许别的程序把导入主文件的功能。只有你再执行主文件的时候,它才等于 __main__。
    #s1.py
    def run():
    print("Run..run..run") if __name__ == "__main__":
    run() # 执行 s1.py 的结果
    """
    Run..run..run
    """ #s2.py
    import s1 # 执行 s2.py 的结果
    """ """

    __name__

本周作业

计算器, +-*/

8*12+(6-(5*6-2)/77+2)*(3-7)+8

需求

  1. 从前到后找,找到第一个(开始)结尾,中间不含有括号
  2. \(中间不包含括号\)
  3. def 处理加减乘除(表达式)
  4. def 处理括号(表达式):
         while True:
               re.split("\(中间不包含括号\)"),表达式,1)

參考資料

[金角大王] Python 之路 Day5 - 常用模块学习

[銀角大王] Python开发【第六篇】:模块

http://www.cnblogs.com/Wxtrkbc/p/5453349.html

http://www.cnblogs.com/wupeiqi/articles/4949995.html

http://www.oschina.net/question/12_9507?fromerr=1XeoRJEp

上一篇:Excel 2010 Alt+; (分号) --- “只选定当前选定区域中的可视单元格”


下一篇:excel设置单元格不可编辑