python模块二(递归,反射,正则表达式)
一、递归,阶乘
递归之实例:
def func(num): """ 1*2*3*4*5... 计算类型形式的阶乘 :param num: 计算阶乘的最大值 :return: 7 * (7 - 1) """ # 如果参数为1,直接返回1 if num == 1: return 1 # 否则返回2 * (2 - 1) return num * func(num - 1) x = func(5) print(x) # ########print########### 120 print(1 * 2 * 3 * 4 * 5) # ########print########### 120
二、反射
反射关键:
反射: 基于字符串的形式去对象(模块)中操作其成员
基于内存操作的
delattr 删除成员
setattr 设置成员
getattr 获取成员
hasattr 检查成员
学习反射之前先了解一下下面的知识
# 定义一个函数名为f1 def f1(): print('F1') # 字符串f1 "f1" # 那么函数名的f1与字符串的f1是否一样 答案是不一样 f1 是 函数名,代表整个函数体 "f1"是 字符串,仅代表字符串本身
现在以一个实例来学习反射
#!/bin/bin/env python # -*-coding:utf-8 -*- def login(): print("登录界面") def loginout(): print("退出界面") def index(): print("主界面")
先对比俩个图
代码块
#!/bin/bin/env python # -*-coding:utf-8 -*- def run(): import reflection select = input("请输入你要访问的URL:") if select == 'login': reflection.login() elif select == 'loginout': reflection.loginout() elif select == 'index': reflection.index() else: print("404") run() # ######################## """ 请输入你要访问的URL:loginout 退出界面 请输入你要访问的URL:login 登录界面 请输入你要访问的URL:index 主界面 请输入你要访问的URL:inde 404 """
代码块
#!/bin/bin/env python # -*-coding:utf-8 -*- def runs(): import reflection res = input("输入你要访问的URL:") if hasattr(reflection, res): func = getattr(reflection, res) func() else: print("404") runs() # ####################### ''' 输入你要访问的URL:index 主界面 输入你要访问的URL:login 登录界面 输入你要访问的URL:loginout 退出界面 输入你要访问的URL:3434 404 '''
以上呢是在同一个模块中做的,那如果是在不同模块中要怎么使用呢???
代码块
# __import__("day6.%s" % m, fromlist=True)
def runs(): # reflection/login res = input("输入你要访问的URL:") m, s = res.split("/") obj = __import__("day6.%s" % m, fromlist=True) # 可以在不同级目录中使用 # print(obj) # <module 'day6.str_module' from 'E:\\PyCharm4.5.2\\PyCharm 文件\\day6\\str_module.py'> # obj = __import__("day6.%s" % m,) # print(obj) # <module 'day6' from 'E:\\PyCharm4.5.2\\PyCharm 文件\\day6\\__init__.py'> if hasattr(obj, s): func = getattr(obj, s) func() else: print("404") runs() # ####################### ''' 输入你要访问的URL:reflection/index 主界面 输入你要访问的URL:reflection/login 登录界面 输入你要访问的URL:reflection/loginout 退出界面 输入你要访问的URL:reflection/3434 404 '''
三、模块
特殊变量
1 # 将文件中的注释添加到文档中 2 __doc__ 3 # .pyc 字节码在哪个路径,然后打印出来 4 __cached__ 5 # 当前py文件所在的路径 6 __file__ 7 # 当前py文件中返回None,被调用输出当前文件的上一级目录名 8 __package__ 9 # 只有执行当前文件的时候,当前文件的特殊变量 __name__ == "__main__" 10 __name__
一个进度条实例
import time import sys def view_bar(num, total): rate = num / total rate_num = rate * 100 # \r 表示替换这个位置 r = "\r%s%d%%" % (['=' * num], rate_num,) # 输出不加换行符 sys.stdout.write(r) # 实时刷新 sys.stdout.flush() # print(r) # view_bar(1, 100) for i in range(1, 101): view_bar(i, 100) time.sleep(0.1)
1、hashlib模块
用于加密相关的操作,代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
import hashlib obj = hashlib.md5(bytes('jdffjdslf', encoding='utf-8')) obj.update(bytes("123", encoding='utf-8')) result = obj.hexdigest() ########################################################## print(result) # e6da8580c5b4c3a6e1b0da4957abd271
import hashlib obj = hashlib.sha1() obj.update(bytes('123', encoding='utf-8')) result = obj.hexdigest() ############################################################## print(result) # 40bd001563085fc35165329ea1ff5c5ecbdbbeef
import hashlib obj = hashlib.sha256() obj.update(bytes('123', encoding='utf-8')) result = obj.hexdigest()
####################################################################### print(result) # a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3
import hashlib obj = hashlib.sha512() obj.update(bytes('123', encoding='utf-8')) result = obj.hexdigest() ####################################################################### print(result) # 3c9909afec25354d551dae21590bb26e38d53f2173b8d3dc3eee4c047e7ab1c1eb8b85103e3be7ba613b31bb5c9c36214dc9f14a42fd7a2fdb84856bca5c44c2
以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。
import hashlib obj = hashlib.md5(bytes('rain', encoding='utf-8')) obj.update(bytes("123", encoding='utf-8')) result = obj.hexdigest() ########################### print(result) # b19575adf69aca85fb4c1523d258a885
python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 再进行处理然后再加密
import hmac obj = hmac.new(bytes("rain", encoding='utf8')) obj.update(bytes("123", encoding='utf8')) result = obj.hexdigest() ########################### print(result) # 1895606979c7fcd5cf926f46a36d096a
可以与hashlib.md5()加密之后做一个对比
2、正则表达式
正则也是一种小型的语言
re模块用于对python的正则表达式的操作
1)导入re模块
import re
2)正则表达式匹配模式
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[...] | 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k' |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
re* | 匹配0个或多个的表达式。 |
re+ | 匹配1个或多个的表达式。 |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
re{ n} | |
re{ n,} | 精确匹配n个前面表达式。 |
re{ n, m} | 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式 |
a| b | 匹配a或b |
(re) | G匹配括号内的表达式,也表示一个组 |
(?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 |
(?-imx) | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 |
(?: re) | 类似 (...), 但是不表示一个组 |
(?imx: re) | 在括号中使用i, m, 或 x 可选标志 |
(?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 |
(?#...) | 注释. |
(?= re) | 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
(?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功 |
(?> re) | 匹配的独立模式,省去回溯。 |
\w | 匹配字母数字 |
\W | 匹配非字母数字 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f]. |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]. |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等. | 匹配一个换行符。匹配一个制表符。等 |
\1...\9 | 匹配第n个分组的子表达式。 |
\10 | 匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式。 |
3)正则表达式修饰符 - 可选标志
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理 解。 |
正则详解
1、match(pattern, string, flags=0)
从起始位置开始根据模型去字符串中匹配指定内容,匹配单个
- 正则表达式
- 要匹配的字符串
- 标志位,用于控制正则表达式的匹配方式
import re obj = re.match('\d+', '123djfjjf') print(obj.group()) # 123 obj = re.match('\d+', 'dj123fjjf') print(obj.group()) # 由于match只匹配开始位置,所以这里会报错
# flags I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE # ignore case L = LOCALE = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale U = UNICODE = sre_compile.SRE_FLAG_UNICODE # assume unicode locale M = MULTILINE = sre_compile.SRE_FLAG_MULTILINE # make anchors look for newline S = DOTALL = sre_compile.SRE_FLAG_DOTALL # make dot match newline X = VERBOSE = sre_compile.SRE_FLAG_VERBOSE # ignore whitespace and comments
2、search(pattern, string, flags=0)
根据模型去字符串中匹配指定内容,匹配单个
import re obj = re.search('\d+', 'dfjs123456') print(obj.group()) # 123456 obj = re.search('\d+', '456dfjs123456') print(obj.group()) # 456
3、findall(pattern, string, flags=0)
上述两中方式均用于匹配单值,即:只能匹配字符串中的一个,如果想要匹配到字符串中所有符合条件的元素,则需要使用 findall。
import re obj = re.findall('\d+', '123jfj123456') print(obj) # ['123', '123456'] obj = re.findall('\d+', 'afsf789sjfj123456') print(obj) # ['789', '123456']
4、sub(pattern, repl, string, count=0, flags=0)
用于替换匹配的字符串
import re content = "123abc456" # 将所有数字替换成abc new_content = re.sub('\d+', 'abc', content) print(new_content) # abcabcabc content = "123abc456" # 只替换第一个匹配到的数字 new_content = re.sub('\d+', 'sb', content, 1) print(new_content) # sbabc456 content = "123ab123c456" # 只替换前二个匹配到的数字 new_content = re.sub('\d+', 'rain', content, 2) print(new_content) # rainabrainc456
5、split(pattern, string, maxsplit=0, flags=0)
根据指定匹配进行分组
import re content = "'1 - 2 * ((60-30+1*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2) )'" new_content = re.split('\*', content) print(new_content) # ["'1 - 2 ", ' ((60-30+1', '(9-2', '5/3+7/3', '99/4', '2998+10', '568/14))-(-4', '3)/(16-3', "2) )'"] content = "'1 - 2 * ((60-30+1*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2) )'" new_content = re.split('\*', content, 1) print(new_content) # ["'1 - 2 ", " ((60-30+1*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2) )'"]
import re content = "'1 - 2 * ((60-30+1*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2) )'" # 以+、-、*、/为分隔符 new_content = re.split('[\+\-\*\/]+', content) # new_content = re.split('\*', content, 1) print(new_content) # ["'1 ", ' 2 ', ' ((60', '30', '1', '(9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14))', '(', '4', '3)', '(16', '3', "2) )'"]
import re inpp = '1-2*((60-30 +(-40-5)*(9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2))' # 将inpp里面的任意空白字符替换为空 inpp = re.sub('\s*', '', inpp) # new_content = re.split('\(([\+\-\*\/]?\d+[\+\-\*\/]?\d+){1}\)', inpp, 1) new_content = re.split('\(([^()]+)\)', inpp, 1) print(new_content) # ['1-2*((60-30+', '-40-5', '*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
6、group和groups
import re a = "123abc456" print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group()) # 123abc456 print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(0)) # 123abc456 print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(1)) # 123 print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(2)) # abc print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).groups()) # ('123', 'abc', '456')
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
字符类
实例 | 描述 |
---|---|
[Pp]ython | 匹配 "Python" 或 "python" |
rub[ye] | 匹配 "ruby" 或 "rube" |
[aeiou] | 匹配中括号内的任意一个字母 |
[0-9] | 匹配任何数字。类似于 [0123456789] |
[a-z] | 匹配任何小写字母 |
[A-Z] | 匹配任何大写字母 |
[a-zA-Z0-9] | 匹配任何字母及数字 |
[^aeiou] | 除了aeiou字母以外的所有字符 |
[^0-9] | 匹配除了数字外的字符 |
正则例子:
匹配手机号
import re phone_str = "hey my name is alex, and my phone number is 13651054607, please call me if you are pretty!" # 完全匹配11位电话号码 m = re.search('([\d]{11})', phone_str) print(m.group()) # 13651054607 phone_str2 = "hey my name is alex, and my phone number is 18651054604, please call me if you are pretty!" # 匹配以1开头并且第二位为[358]的11位电话号话 m = re.search('(1)([358]\d{9})', phone_str2) print(m.group()) # 18651054604
匹配IP V4
import re ip_addr = "inet 192.168.60.223 netmask 0xffffff00 broadcast 192.168.60.255" m = re.search('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_addr) print(m.group()) # 192.168.60.223 ip_addr = "inet 192.168.60.223 netmask 0xffffff00 broadcast 192.168.60.255" m = re.findall('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_addr) print(m) # ['192.168.60.223', '192.168.60.255']
分组匹配地址
import re contactInfo = 'Oldboy School, Beijing Changping Shahe: 010-8343245'
m = re.search(r'(\w+), (\w+) (\S+)', contactInfo) # 分组 # School, Beijing Changping
m = re.search(r'(\w+) (\w+): (\S+)', contactInfo) # 分组 # Changping Shahe: 010-8343245
print(m.group()) # School, Beijing Changping print(m.group(0)) # School, Beijing Changping print(m.group(1)) # School print(m.group(2)) # Beijing print(m.group(3)) # Changping
匹配email
import re email = "rain_linux@163.com http://www.oldboyedu.com" # \w中包含_下划线 m = re.search(r"[\w0-9.a-z]{0,26}@[0-9.a-z]{0,20}.[0-9a-z]{0,8}", email) print(m.group()) # rain_linux@163.com
未完待续!!!