51 查看对象类型
class Student(object):
def __init__(self, id, name):
self.id = id
self.name = name
def __repr__(self):
return 'id=' + self.id + ', name=' + self.name
xiaoming = Student(id='001',name='xiaoming')
print(type(xiaoming))
-><class '__main__.Student'>
type(tuple())
->tuple
52 聚合迭代器ZIP
# 创建一个聚合了来自每个可迭代对象中的元素的迭代器:
x = [3, 2, 1]
y = [4, 5, 6]
print(list(zip(y, x)))
a = range(5)
b = list('abcde')
print(b)
print([str(y) + str(x) for x, y in zip(a, b)])
53 nonlocal 用于内嵌函数中
# 关键词 nonlocal 常用于函数嵌套中,声明变量 i 为非局部变量;
# 如果不声明,i+=1 表明 i 为函数 wrapper 内的局部变量,因为在 i+=1 引用(reference) 时,i 未被声明,所以会报 unreferenced variable 的错误。
import time
def exceter(f, n):
i = 0
t1 = time.time()
def wrapper():
try:
f()
except Exception as e:
nonlocal i
i += 1
print(f'{e.args[0]}:{i}')
t2 = time.time()
if i == n:
print(f'spending time:{round(t2 - t1, 2)}')
return wrapper
54 global 声明全局变量
# 先回答为什么要有 global,一个变量被多个函数引用,想让全局变量被所有函数共享。有的伙伴可能会想这还不简单,这样写:
i = 5
def f():
print(i)
def g():
print(i)
pass
f()
g()
f 和 g 两个函数都能共享变量 i,程序没有报错,所以他们依然不明白为什么要用global. 但是,如果我想要有个函数对 i 递增,这样:
def h():
i += 1
h()
此时执行程序,bang, 出错了!抛出异常:UnboundLocalError,原来编译器在解释 i+=1 时会把 i 解析为函数 h() 内的局部变量,很显然在此函数内,编译器找不到对变量 i 的定义,所以会报错。
global 就是为解决此问题而被提出,在函数 h 内,显示地告诉编译器 i 为全局变量,然后编译器会在函数外面寻找 i 的定义,执行完 i+=1 后,i 还为全局变量,值加 1:
i = 0
def h():
global i i += 1
h()
print(i)
55 链式比较
i = 3
print(1 < i < 3) # False
print(1 < i <= 3) # True
56 不用else和if实现计算器
from operator import *
def calulator(a, b, k):
return{
'+': add,
'-': sub,
'/': mul,
'**': pow
}[k](a,b)
calulator(1, 2, '+') # 3
calulator(3, 4, '**') # 81
57 链式操作
from operator import (add, sub)
def add_or_sub(a, b, oper):
return (add if oper == '+' else sub)(a, b)
add_or_sub(1, 2, '-') # -1
58 交换两元素
def swap(a, b)
return b, a
print(swap(1, 0)) # (0, 1)
59 去最求平均
def score_mean(lst):
lst.sort()
lst2 = lst[1:(len(lst)-1)]
return round((sum(lst2)/len(lst2)), 1)
lst=[9.1, 9.0,8.1, 9.7, 19,8.2, 8.6,9.8]
score_mean(lst) # 9.1
60 打印99乘法表
打印出如下格式的乘法表
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 ␣ ,→9*9=81
一共有 10 行,第 i 行的第 j 列等于:j*i, 其中, i 取值范围:1<=i<=9 j 取值范围:1<=j<=i 根据例子分析的语言描述,转化为如下代码:
for i in range(1, 10):
for j in range(1, i+1):
print('%d * %d = %d' %(j,i,j*i), end='\t')
print()
61 全展开
# 对于如下数组:
[[[1,2,3],[4,5]]]
如何完全展开成一维的。这个小例子实现的flatten是递归版,两个参数分别表示带展开的数组,输出数组。
from collections.abc import *
def flatten(lst, out_lst=None):
if out_lst is None:
out_lst = []
for i in lst:
if isinstance(i, Iterable): #判断 i 是否可迭代
flatten(i, out_lst) #尾数递归
else:
out_lst.append(i) # 产生结果
return out_lst
#调用flatten:
print(flatten([[1,2,3],[4,5]]))
print(flatten([[1,2,3],[4,5]], [6,7]))
print(flatten([[[1,2,3],[4,5,6]]]))
62 列表等分
from math import ceil
def divide(lst, size):
if size <= 0:
return [lst]
return [lst[i * size: (i + 1) * size] for i in range(0, ceil(len(lst) / size))]
r = divide([1, 3, 5, 7, 9], 2)
print(r)
-> [[1, 3], [5, 7], [9]]
r = divide([1, 3, 5, 7, 9], 2)
print(r)
-> [[1, 3, 5, 7, 9]]
63 列表压缩-过滤空的
def filter_false(lst):
return list(filter(bool, lst))
r = filter_false([None, 0, False, '', [], 'ok', [1,2]])
print(r)
64 最长的列表是哪个
def max_length(*lst):
return max(*lst, key=lambda v: len(v))
r = max_length([1,2,3], [4,5,6,7], [8])
print(f'更长的列表是{r}')
-> 更长的列表是[4, 5, 6, 7]
65 求众数
def top1(lst):
return max(lst, default='列表为空', key=lambda v: lst.count(v))
lst = [1, 3, 3, 2, 1, 1, 2]
r = top1(lst)
print(f'{lst}中出现次数最多的元素为:{r}')
-》 [1, 3, 3, 2, 1, 1, 2]中出现次数最多的元素为:1
66 多表之最
def max_lists(*lst):
return max(max(*lst, key=lambda v : max(v)))
r = max_lists([1,2,3], [6,7,8], [4,5])
print(r)
->8
67 列表查重
def has_duplicates(lst):
return len(lst) == len(set(lst))
x = [1,1,2,2,3,2,3,4,5,6]
y = [1,2,3,4,5]
has_duplicates(x) # False
has_duplicates(y) # True
68 列表反转
def reverse(lst):
return lst[::-1]
x = [1, 1, 2, 2, 3, 2, 3, 4, 5, 6]
print(reverse(x))
-》 [6, 5, 4, 3, 2, 3, 2, 2, 1, 1]
69 浮点数等差数列
def rang(start, stop, n):
start, stop, n = float('%.2f' % start), float('%.2f' % stop), int('%.d' % n)
step = (stop - start) / n
lst = [start]
while n > 0:
start, n = start + step, n - 1
lst.append(round((start), 2))
return lst
r = rang(1, 8, 10)
print(r)
C:\Python36\python.exe C:/mycode/awesome-python-io/run_test_code/run_基本功_python小例子.py
[1.0, 1.7, 2.4, 3.1, 3.8, 4.5, 5.2, 5.9, 6.6, 7.3, 8.0]
70 按条件分组
def bif_by(lst, f):
return [[x for x in lst if f(x)], [x for x in lst if not f(x)]]
records = [25, 89, 31, 34]
r = bif_by(records, lambda x: x < 80)
print(r)
-》 [[25, 31, 34], [89]]
71 map 实现向量运算
# 多序列运算函数-map(fuction, iterabel, iterabel2)
lst1 = [1, 2, 3, 4, 5, 6]
lst2 = [3, 4, 5, 6, 3, 2]
r = list(map(lambda x, y: x * y + 1, lst1, lst2))
print(r)
C:\Python36\python.exe C:/mycode/awesome-python-io/run_test_code/run_基本功_python小例子.py
[4, 9, 16, 25, 16, 13]
72 值最大的字典
def max_pairs(dic):
if len(dic) == 0:
return dic
max_val = max(map(lambda v: v[1], dic.items()))
return [item for item in dic.items() if item[1] == max_val]
r = max_pairs({'a': -10, 'b': 5, 'c': 3, 'd': 5})
print(r)
C:\Python36\python.exe C:/mycode/awesome-python-io/run_test_code/run_基本功_python小例子.py
[('b', 5), ('d', 5)]
73 合并两个字典
def merge_dict(dict1, dict2):
return {**dict1, **dict2} # python3.5后支持一行代码实现合并字典
r = merge_dict({'a': 1, 'b': 2}, {'c': 3})
print(r)
C:\Python36\python.exe C:/mycode/awesome-python-io/run_test_code/run_基本功_python小例子.py
{'a': 1, 'b': 2, 'c': 3}
# 一行代码实现
# 一行代码实现
a = {'c': 3}
b = {'a': 1, 'b': 2}
a.update(b)
print(a)
74 topn字典
from heapq import nlargest
# 返回字典d 前n个最大值对应的键
def topn_dict(d, n):
return nlargest(n, d, key=lambda k: d[k])
r = topn_dict({'a': 1, 'b': 8, 'c': 8, 'd': 11}, 3)
print(r)
C:\Python36\python.exe C:/mycode/awesome-python-io/run_test_code/run_基本功_python小例子.py
['d', 'b', 'c']
75 异位词
from collections import Counter
# 检查两个字符是否 相同字母异序词,简称:互为变位词
def anagram(str1, str2):
return Counter(str1) == Counter(str2)
r = anagram('eleven+two', 'twelve+one') # True 这是一对神器的变位词
print(r)
anagram('eleven', 'twelve') # False
76 逻辑上合并字典
(1) 看73,修改 merged[‘x’]=10,dic1 中的 x 值不变,merged 是重新生成的一个新字典。
(2)但是,ChainMap 却不同,它在内部创建了一个容纳这些字典的列表。因此使用
ChainMap 合并字典,修改 merged[‘x’]=10 后,dic1 中的 x 值改变,如下所示:
from collections import ChainMap
dict1 = {'x': 1, 'y': 2}
dict2 = {'y': 3, 'z': 4}
merged2 = ChainMap(dict1, dict2)
print(merged2)
C:\Python36\python.exe C:/mycode/awesome-python-io/run_test_code/run_基本功_python小例子.py
ChainMap({'x': 1, 'y': 2}, {'y': 3, 'z': 4})
77 命名元组提高可读性
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y', 'z']) # 定义名为Point的元组,字段数组有x,y,z
lst = [Point(1.5, 2, 3.0), Point(-0.3, -1.0, 2.1), Point(1.3, 2.8, -2.5)]
print(lst[0].y - lst[1].y) # 3
78 样本抽样
# 使用sample抽样,如下例子从100个样本中随机抽样10个
from random import randint, sample
lst = [randint(0, 50) for _ in range(100)]
print(lst[:5])
lst_sample = sample(lst, 10)
print(lst_sample)
79 重洗数据集
# 使用shuffle 来冲洗数据集,值得注意"shuffle"是对lst就地(in place)洗牌,节省存储空间
from random import shuffle
from random import randint
lst = [randint(0, 50) for _ in range(100)]
print(lst)
shuffle(lst)
print(lst[:5])
80 10个均匀分布的坐标点
# random模块中的uniform(a,b)生成[a,b)内的一个随机数,如下生成10个均匀分布的二维坐标点
from random import uniform
r = [(uniform(0, 10), uniform(0, 10)) for _ in range(10)]
print(r)
81 10个高斯分布的坐标点
random模块中的gauss(u, sigma)生成均值为u, 标准差为sigma的满足高斯分布的值,如下生成10个二维坐标点,样本误差(y-2*x-1)满足均值为0,标准差为1的高斯分布:
from random import gauss
x = range(10)
y = [2 * xi + 1 + gauss(0, 1) for xi in x]
points = list(zip(x, y))
print(points)
82 chain高效串联多个容器对象
chain函数串联a和b,兼顾内存效率同时写法更加优雅
from itertools import chain
a = [1, 3, 4, 0]
b = (2, 4, 6)
for i in chain(a, b):
print(i)
83 操作函数对象
def f():
print('i\'m f')
def g():
print('i\'m g')
[f,g][1]()
84 生成逆序序列
list(range(10, -1, -1)) # [10,9,8,7,6.5,4,3,2,1,0]
第三个参数为负时,表示从第一个参数开始递减,终止到第二个参数(不包括此边界)
85 函数的五类参数使用例子
python 五类参数:位置参数,关键字参数,默认参数,可变位置或关键字参数的使用
def f(a, *b, c=10, **d):
print(f'a:{a}, b:{b}, c:{c}, d:{d}')
默认参数“c”不能位于可变关键字参数“d”后。
调用f: In [10]: f(1,2,5,width=10,height=20) a:1,b:(2, 5),c:10,d:{‘width’: 10, ‘height’: 20}
可变位置参数b实参后被解析为元组(2, 5);而取得默认值10;d被解析为字典
再次调用f: In [11]: f(a=1,c=12) a:1,b:(),c:12,d:{}
a=1 传入时 a 就是关键字参数,b,d 都未传值,c 被传入 12,而非默认值。 注意观察参数 a, 既可以 f(1), 也可以 f(a=1) 其可读性比第一种更好,建议使 用 f(a=1)。如果要强制使用 f(a=1),需要在前面添加一个星号:
def f(*, a, *b):
print(f'a:{a}, b:{b}')
此 时 f(1) 调 用, 将 会 报 错:TypeError: f() takes 0 positional arguments but 1 was given 只能 f(a=1) 才能 OK. 说明前面的 * 发挥作用,它变为只能传入关键字参数,那么如何查看这个参数的 类型呢?借助 python 的 inspect 模块:
for name, val in signature(f).parameters.items():
print(name, val.kind)
a KEYWORD_ONLY
b VAR_KEYWORD
可看到参数 a 的类型为 KEYWORD_ONLY,也就是仅仅为关键字参数。 但是,如果 f 定义为
def f(a, *b):
print(f'a:{a}, b:{b}')
查看参数类型:
for name, val in signature(f).parameters.items():
print(name, val.kind)
a POSITIONAL_OR_KEYWORD
b VAR_POSITIONAL
可以看到参数 a 既可以是位置参数也可是关键字参数。
86 使用slice对象
生成关于蛋糕的序列cake 1:
cake1 = list(range(5, 0, -1))
b = cake1[1:10:2]
print(b)
->[4, 2]
print(cake1)
-> [5, 4, 3, 2, 1]
再生成一个序列:
from random imporr randint
cake2 = [randint(1, 100) for _ in range(100)]
# 同样以间隔为2切前10个元素, 得到切片d
d = cake2[1:10:2]
print(d)
-> [75, 33, 63, 93, 15]
你看,我们使用同一种切法,分别切开两个蛋糕 cake1,cake2. 后来发现这种切法极 为经典,又拿它去切更多的容器对象。 那么,为什么不把这种切法封装为一个对象呢?于是就有了 slice 对象。 定义 slice 对象极为简单,如把上面的切法定义成 slice 对象:
perfect_cake_slice_way = slice(1,10,2) # 去切 cake1
cake1_slice = cake1[perfect_cake_slice_way]
cake2_slice = cake2[perfect_cake_slice_way]
In [11]: cake1_slice
Out[11]: [4, 2]
In [12]: cake2_slice
Out[12]: [75, 33, 63, 93, 15]
与上面的结果一致。 对于逆向序列切片,slice 对象一样可行:
a = [1,3,5,7,9,0,3,5,7]
a_ = a[5:1:-1]
named_slice = slice(5,1,-1)
a_slice = a[named_slice]
In [14]: a_
Out[14]: [0, 9, 7, 5]
In [15]: a_slice
Out[15]: [0, 9, 7, 5]
频繁使用同一切片的操作可使用 slice 对象抽出来,复用的同时还能提高代码可读 性。
上面的基础实际为86个
Python 字符串和正则22个
字符串无所不在,字符串的处理也是最常见的操作。本章节将总结和字符串处理相关的 一切操作。主要包括基本的字符串操作;高级字符串操作之正则。目前共有 20 个小例 子
1 反转字符串
str = "python"
# 方法1
''.join(reversed(str))
# 方法2
str[::-1]
2 字符串切片操作
# 字符串切片操作——查找替换 3 或 5 的倍数
[ str("java"[i%3*4:] + "python"[i%5*6:]) for i in range(1,15)]
OUT[1]:['1',
'2',
'java',
'4',
'python',
'java',
'7',
'8',
'java',
'python',
'11',
'java',
'13',
'14']
3 join 串联字符串
mystr = ['1', '2', 'java', '4','python']
','.join(mystr) # 用逗号连接字符串
4 字符串的字节长度
def str_byte_len(mystr):
return (len(mystr.encode('utf-8')))
str_byte_len('i love python') # 13(个字节)
str_byte_len('字符') # 6(个字节)
5 查找第一个匹配串
import re
s = 'i love python very much'
pat = 'python'
r = re.search(pat, s)
print(r.span()) # (7,13)
6 查找所有1的索引
s = '山东省潍坊市青州第 1 中学高三 1 班'
pat = '1'
r = re.finditer(pat,s)
for i in r:
print(i)
7 \d 匹配数字0-9
findall 找出全部位置的所有匹配
s = '一共 20 行代码运行时间 13.59s'
pat = r'\d+' # + 表示匹配数字 (\d 表示数字的通用字符)1 次或多次
print(r)
-> ['20', '13', '59']
8 匹配浮点数和整数
? 表示前一个字符匹配 0 或 1 次
s = '一共 20 行代码运行时间 13.59s'
pat = r'\d+\.?\d+' # ? 表示匹配小数点 (\.)0 次或 1 次,这种写法有个小bug,不能匹配到个位数的整数
r = re.findall(pat, s)
print(r)
-> ['20', '13.59']
# 更好的写法:
pat = r'\d+\.\d+|\d+' # A| B, 匹配A失败才匹配B
9 ^ 匹配字符串的开头
s = 'This module provides regular expression matching operations, similar to those found in Perl'
pat = r'^[emrt]' # 查找以字符 e,m,r 或 t 开始的字符串
r = re.findall(pat,s)
print(r)
# [], 因为字符串的开头是字符`T`,不在 emrt 匹配范围内,所以返回为空
IN [11]: s2 = 'email for me is guozhennianhua@163.com'
re.findall('^[emrt].*',s2)# 匹配以 e,m,r,t 开始的字符串,后面是多个任意字符
Out[11]: ['email for me is guozhennianhua@163.com']
10 re.I 忽略大小写
s = 'That'
pat = r't' r = re.findall(pat,s,re.I)
In [22]: r
Out[22]: ['T', 't']
11 理解 compile 的作用
如果要做很多次匹配,可以先编译匹配串:
import re
pat = re.compile('\W+') # \W 匹配不是数字和字母的字符
has_special_chars = pat.search('ed#2@edc')
if has_special_chars:
print(f'str contains special characters:{has_special_chars.
,→group(0)}')
### 输出结果:
# str contains special characters:#
### 再次使用 pat 正则编译对象 做匹配
again_pattern = pat.findall('guozhennianhua@163.com')
if '@' in again_pattern:
print('possibly it is an email')
12 使用 () 捕获单词,不想带空格
s = 'This module provides regular expression matching operations␣ ,similar to those found in Perl'
pat = r'\s([a-zA-Z]+)' r = re.findall(pat,s)
print(r) #['module', 'provides', 'regular', 'expression', 'matching
,', 'operations', 'similar', 'to', 'those', 'found', 'in', 'Perl']
看到提取单词中未包括第一个单词,使用? 表示前面字符出现 0 次或 1 次,但是此 字符还有表示贪心或非贪心匹配含义,使用时要谨慎。
s = 'This module provides regular expression matching operations␣ ,similar to those found in Perl'
pat = r'\s?([a-zA-Z]+)'
r = re.findall(pat,s)
print(r) #['This', 'module', 'provides', 'regular', 'expression',
,'matching', 'operations', 'similar', 'to', 'those', 'found', 'in',
, 'Perl']
13 split 分割单词
使用以上方法分割单词不是简洁的,仅仅是为了演示。分割单词最简单还是使用 split 函数。
s = 'This module provides regular expression matching operations␣ ,→similar to those found in Perl'
pat = r'\s+' r = re.split(pat,s)
print(r) # ['This', 'module', 'provides', 'regular', 'expression',
,→'matching', 'operations', 'similar', 'to', 'those', 'found', 'in',
,→ 'Perl']
### 上面这句话也可直接使用 str 自带的 split 函数:
s.split(' ') # 使用空格分隔
### 但是,对于风格符更加复杂的情况,split 无能为力,只能使用正则
s = 'This,,, module ; \t provides|| regular ; '
words = re.split('[,\s;|]+',s) # 这样分隔出来,最后会有一个空字符串
words = [i for i in words if len(i)>0]
14 match 从字符串开始位置匹配
注意 match,search 等的不同: 1) match 函数
import re
### match
mystr = 'This'
pat = re.compile('hi')
pat.match(mystr) # None
pat.match(mystr,1) # 从位置 1 处开始匹配
Out[90]: <re.Match object; span=(1, 3), match='hi'>
2) search 函数 search 是从字符串的任意位置开始匹配
In [91]: mystr = 'This' ...: pat = re.compile('hi') ...: pat.search(mystr)
Out[91]: <re.Match object; span=(1, 3), match='hi'>
15 替换匹配的子串
sub 函数实现对匹配子串的替换
content="hello 12345, hello 456321"
pat=re.compile(r'\d+') # 要替换的部分
m=pat.sub("666",content)
print(m) # hello 666, hello 666
16 贪心捕获
(.*) 表示捕获任意多个字符,尽可能多的匹配字符
content='<h>ddedadsad</h><div>graph</div>bb<div>math</div>cc'
pat=re.compile(r"<div>(.*)</div>") # 贪婪模式
m=pat.findall(content)
print(m) # 匹配结果为: ['graph</div>bb<div>math']
17 非贪心捕获
仅添加一个问号 (?),得到结果完全不同,这是非贪心匹配,通过这个例子体会贪心和 非贪心的匹配的不同。
content='<h>ddedadsad</h><div>graph</div>bb<div>math</div>cc'
pat=re.compile(r"<div>(.*?)</div>") m=pat.findall(content)
print(m) # ['graph', 'math']
18 常用元字符总结
. 匹配任意字符
^ 匹配字符串开始位置
$ 匹配字符串中结束的位置
* 前面的原子重复 0 次、1 次、多次
? 前面的原子重复 0 次或者 1 次 + 前面的原子重复 1 次或多次
{n} 前面的原子出现了 n 次
{n,} 前面的原子至少出现 n 次
{n,m} 前面的原子出现次数介于 n-m 之间
( ) 分组, 需要输出的部分
19 常用通用字符总结
\s 匹配空白字符
\w 匹配任意字母/数字/下划线
\W 和小写 w 相反,匹配任意字母/数字/下划线以外的字符
\d 匹配十进制数字
\D 匹配除了十进制数以外的值
[0-9] 匹配一个 0-9 之间的数字
[a-z] 匹配小写英文字母
[A-Z] 匹配大写英文字母
20 爬取百度首页标题
import re
from urllib import request
# 爬虫爬取百度首页内容
data=request.urlopen("http://www.baidu.com/").read().decode()
# 分析网页, 确定正则表达式
pat=r'<title>(.*?)</title>'
result=re.search(pat,data)
print(result) <re.Match object; span=(1358, 1382), match='<title> 百
度一下,你就知道</title>'>
result.group() # 百度一下,你就知道
21 批量转化为驼峰格式 (Camel)
数据库字段名批量转化为驼峰格式 分析过程
# 用到的正则串讲解
# \s 指匹配: [ \t\n\r\f\v]
# A|B:表示匹配 A 串或 B 串
# re.sub(pattern, newchar, string):
# substitue 代替,用 newchar 字符替代与 pattern 匹配的字符所有.
# title(): 转化为大写,例子:
# 'Hello world'.title() # 'Hello World'
# print(re.sub(r"\s|_|", "", "He llo_worl\td"))
s = re.sub(r"(\s|_|-)+", " ", 'some_database_field_name').title().replace(" ", "") # 结果: SomeDatabaseFieldName
# 可以看到此时的第一个字符为大写,需要转化为小写
s = s[0].lower()+s[1:] # 最终结果
整理以上分析得到如下代码:
import re
def camel(s):
s = re.sub(r"(\s|_|-)+", " ", s).title().replace(" ", "")
return s[0].lower() + s[1:]
# 批量转化
def batch_camel(slist):
return [camel(s) for s in slist]
测试结果:
s = batch_camel(['student_id', 'student\tname', 'student-add'])
print(s)
# 结果
['studentId', 'studentName', 'studentAdd']
22 密码安全检查
密码安全要求:1) 要求密码为 6 到 20 位; 2) 密码只包含英文字母和数字
pat = re.compile(r'\w{6,20}') # 这是错误的,因为\w 通配符匹配的是字母,数字和下
划线,题目要求不能含有下划线
# 使用最稳的方法:\da-zA-Z 满足`密码只包含英文字母和数字`
pat = re.compile(r'[\da-zA-Z]{6,20}')
选用最保险的 fullmatch 方法,查看是否整个字符串都匹配
pat.fullmatch('qaz12') # 返回 None, 长度小于 6
pat.fullmatch('qaz12wsxedcrfvtgb67890942234343434') # None 长度大于 22
pat.fullmatch('qaz_231') # None 含有下划线
pat.fullmatch('n0passw0Rd')
Out[4]: <re.Match object; span=(0, 10), match='n0passw0Rd'>
【环境】 win10_x64 + python3.6.5
【Me】 https://github.com/Valuebai/ https://valuebai.github.io/
【参考】 1、出处:https://github.com/jackzhenguo/python-small-examples