源代码编译过程
python => python byte code(python字节码) <= python virtual machine
py => pyc <= pvm
REPL:python控制台:R(read)、E(evaluate)、P(print)、L(loop)
数据类型
数据类型可以粗暴的分为数字类型和非数字类型。
-
数字类型包括整型、长整型、浮点型和复数型。
-
非数字型包括字符串、元组、列表和字典。
特点可以归纳为:
- 非数字类型的共同的:都可以切片、链接(+)、重复(*)、取值(a[0]) 等运算
- 字符串、列表、元组的截取方式相同:
名称[头下标, 尾下标]
,下标是从0开始算起,可以是正数也可以是负数,下标为空表示取到头或取到尾。开始截取时包含了边界,但不包含结束边界,如name[0,5]
,取的是0~4不包含5。 - 非数字类型的不同点:列表可以直接赋值而元组不可以。字典使用
dict[key] = value
的方式赋值。 - 元组不能再次赋值,列表可以。
非数字类型
序列
在python中,序列就是一组按顺序排列的值(数据集合)
在python中存在三种内置的序列类型
- 字符串
- 列表
- 元组
优点:
- 支持索引和切片的操作
特征
- 第一个正索引为0,指向左端,第一个索引为负数的时候,指向的是右端
列表
特征:
- 有序
- 支持增删改查
- 数据项(数据内容)可变,地址不会改变
- 用[]表示列表类型,数据项之间用逗号分割,数据项可以是任何类型的数据
- 支持索引和切片
列表常用方法:
listname.append(item)
在列表后面追加元素listname.count(元素)
统计某个元素出现次数listname.extend()
拓展,相当于批量添加listname.index(item)
获取指定元素索引listname.insert(index, item)
在指定位置插入listname.pop([index=-1])
删除一个元素(默认为最后一个),并返回该元素listname.remove(item)
移除左边找到的第一个元素del listname[下标]
删除列表对应下标的元素listname.reverse()
反转列表listname.sort()
排序;reverse=True
倒序isinstance(listname,list)
判断listname
是否为列表类型len(listname)
数组元素个数listname.clear()
清空元素- 批量赋值
t1,t2,t3,t4 = listname
ps:被赋值的变量数量必须和list中的元素数量相当
元组
特征:
- 不可变序列;创建之后不能修改
- 不可变
- 用 () 创建元组类型,数据项用逗号分割
- 可以是任何类型
- 元组中只有一个元素时,要加上逗号,否则解释器将会当作整形处理
- 支持切片
创建:
- 小括号:
tup(item1, item2)
- 使用构造函数:
tup = tuple(item1, item2)
- 空元组:
tup=()
;tup=tuple()
- 元组中如果只有一个元素:
tup=(item,)
为什么要将元组设计成不可变序列:
- 多任务环境下,同时操作对象时不需要加锁
注意事项:元组中存储的是对象的引用
- 元组存储的元素本身是不可变对象如字符串,则不能再改变
- 但如果存储的是数组,则可以通过数组的方法改变数组内的内容
元组的遍历:
- for …… in ……
t = tuple(('Python','Hello',90))
for item in t:
print(item)
修改元组:由于元组不可变,所以不能直接在原有的元组中改变,而是新创建一个元组。如需要拼接两个元组:tup3 = tup1 + tup2
。
删除元组:元组的元素是不可删除的,但可以用del tup
的方式删除整个元组。
字典
特征:
- 可变
- 键值对
- 无序
创建:
{key:value,key2:value2}
:使用花括号dict(key=xxx,value=yyyy)
:内置函数dict()- 空字典
d={}
:字典生成式
获取:
字典名[key]
=> 不存在报错get(key)
=>不存在返回none => 可通过 get(key,help) 在不存在指定对应关系时输出help内容
判断:
key in xxx
: 判断是否在xxx变量中存在key,存在true,否则falsekey not in xxx
:判断是否在xxx变量中存在key,存在false,否则true
删除:
del 字典名[key]
:删除指定键值对字典名.clear()
:清空指定字典
修改:
字典名[key] = new value
:修改值
更新:
字典名.update(另一个字典)
:将一个字典内容添加到另一个字典中
获取字典视图:
keys()
:获取字典中所有keyvalues()
:获取字典中所有的valueitems()
:获取所有key.value对
字典元素遍历:
for item in xxx
特点:
- 键值对一一对应,key不允许重复,值可以重复
- key必须是不可变对象
- 会占用较大内存
- 可根据需求动态伸缩
集合
特征:
- 可变序列
- python提供的内置数据结构
- 可以理解为没有value的字典
- 不能有重复元素(会自动去除)
创建:
- 使用{}花括号创建
set()
:使用内置函数set()s = set(range(6))
- 空集合:
s = set()
判断:
in
not in
新增:
集合名.add()
:一次添加一个集合名.update()
:一次添加多个
删除:
集合名.remove()
:元素不存在则抛出异常集合名.discard()
:即使元素不存在也不会抛出异常集合名.pop()
:删除任意一个元素(因为集合是无序的)集合名.clear()
:清空
集合间的关系:
- 判断集合之间是否相等 = / !=
- 判断集合是否是另一个集合的子集 集合A.issubset(集合B) => 是为True
- 判断集合是否是另一个集合的超集 集合A.issuperset(集合B) => 是为True
- 判断两个集合是否有交集 集合A.isdisjoint(集合B) => 是为False
集合的数学操作:
# 交集
s1 = {10, 20, 30, 40}
s2 = {20, 30, 40, 50, 60}
print(s1.intersection(s2)) # {20, 30, 40}
print(s1 & s2) # intersection() 与 & 等价,交集操作
# 并集
s3 = s1.union(s2) # {10,20,30,40,50,60}
s3_1 = s1 | s2
# 差集
s4 = s1.difference(s2) # {10}
s4_1 = s1 - s2
# 对称差集
s5 = s1.symmetric_difference(s2) # {10, 50, 60}
s5_1 = s1^ s2
字符串
字符串特点
特点:
- 基本数据类型
- 不可变字符序列
- 字符串驻留机制:相同的字符串赋值给不同的变量时,不会开辟新的内存空间
字符串驻留机制
- 字符串的长度为0或1时
- 符合标识符的字符串(字母数字下划线)
- 字符串只在编译时进行驻留,而非运行时
- [-5, 256]
- sys中的intern方法强制2个字符串指向同一个对象
- Pycharm对于字符串进行了优化(如使得不符合标识符的字符串也驻留)
a = 'Python'
b = "Python"
c = '''Python'''
print(a,id(a))
print(b,id(b))
print(c,id(c)) # 打印同样的地址
字符串驻留机制的优缺点:
- 当需要值相同的字符串时,可以直接从字符串池里拿来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串是会比较影响性能的
- 在需要进行字符串拼接时建议使用STR类型的join方法,而非直接使用+,因为join方法是先计算出所有字符串的长度,然后再拷贝,只new一次对象,效率更高
常用方法
反向遍历字符串:str[::-1]
查询方法
方法名称 | 作用 |
---|---|
index() | 查找子串substr第一次出现的位置,如果查找的子串不存在则抛出ValueError |
rindex() | 查找子串substr最后一次…… |
find() | 查找子串substr第一次出现的位置,不存在返回-1 |
rfind() | ……最后一次…… |
大小写转换
方法名 | 作用 |
---|---|
upper() | 所有字符大写 |
lower() | 所有字符小写 |
swapcase() | 大变小,小变大 |
capitalize() | 首字符大写,其余小写 |
title() | 每个单词首字符大写,其余小写 |
无论是哪种方法都将创建新的字符串对象
对齐
方法名 | 作用 |
---|---|
center() | 居中对齐,第一个参数为指定宽度;第二个为间隔填充符,默认为空格;指定宽度小于实际宽度则返回原字符串 |
ljust() | 左对齐…… |
rjust() | 右对齐…… |
zfill() | 右对齐,左边用0填充,仅接收一个参数:指定宽度,如果指定宽度小于…… |
拆分
方法名 | 作用 |
---|---|
split() | 从字符串的左边开始拆分,默认的拆分字符是空格字符串,返回的值都是一个列表 |
通过参数sep指定分割符(分割的依据) | |
通过参数maxsplit指定拆分字符串时的最大拆分次数,经过最大拆分之后,剩余的子串会单独作为一部分 | |
rsplit() | 从字符串的右边开始拆分,默认的拆分字符是空格字符串,返回的值都是一个列表 |
通过参数sep指定分割符 | |
通过maxsplit…… |
判断
方法名 | 作用 |
---|---|
isidentifier() | 判断是否为合法标识符 |
isspace() | 判断是否全部由空白字符组成(回车、换行、水平制表符 |
isalpha() | 判断字符串全都由字母组成 |
isdecimal() | 判断是否全部由十进制数字组成 |
isnumeric() | 判断是否全部由数字组成(包含汉字中的数字和罗马数字) |
isalnum() | 判断是否全部由字母和数字组成 |
替换、合并
方法名 | 作用 |
---|---|
replace() | 第一个参数:指定被替换的字符串;第二个参数:指定替换的字符串,返回替换后的字符串,替换前的不会变化;第三个参数:指定最大替换次数 |
join() | 将列表或元组中的字符串合并成一个字符串(如果参数为字符串而不是列表和元组会将该字符串进行分隔'*'.join('python') => 输出p*y*t*h*o*n |
比较
运算符:>、<、==、<=、>=、!=
规则:
- 首先比较两个字符串中的第一个字符
- 如果相等则继续比较下一个字符,依次进行,直到两个字符串的字符不相等
- 比较结果为两个字符串的比较结果
- 后续字符串中的所有字符将不再被比较
原理:
- 两个字符进行比较时,比较的是
ordinal value(原始值)
,可通过ord()函数进行比较 - ord()函数对应chr()函数
==和is的区别:
==比较的是内容,is比较的是内存地址
字符串切片
[start:end:step]
s = 'hello,python'
print(s[1:5:1]) # =>out:ello
print(s[::2]) # =>out:hlopto 默认0开始,步长为2,两个元素之间的索引间隔为2
print(s[::-1]) # =>out:nohtyp,olleh 倒序
print(s[-6::1]) # =>out:python 以最后一位作为0,则p为-6
格式化输出
方式一:
%s
:字符串%i / %d
:整数%f
:浮点数
name = '张三'
age = 20
print('%s今年%d岁' % (name,age))
方式二:
{}
print('我叫{0},今年{1}'.format(name,age))
方式二plus:推荐
print(f'{name}今年{age}岁')
注意:
- %10d 10代表宽度,不足则在前方补空格
- %.3f .3表示精度:保留浮点数的三位小数
- 宽度和精度可以同时使用
- 方式二 可以通过
print('{0:.3}'.format(3.1415926))
实现保留三位数的效果,而不是三位小数,如果仅为了保留三位小数则格式为**{0:.3f}**;同时保有精度和宽度:{:10.3f},0为占位符顺序,可省略
字符串的编码转换
s = '天涯共此时'
# 编码
s.encode(encoding='GBK') # GBK编码格式中 中文占两个字节
s.encode(encoding='UTF-8') # UTF-8格式中,中文占三个字节
# 解码
byte = s.encode(encoding='GBK') # 编码
byte.decode(encoding='GBK') # 解码
python3种bytes、hex、字符串之间相互转换
- 字符串转bytes
"""
eg:
'0123456789ABCDEF0123456789ABCDEF'
b'0123456789ABCDEF0123456789ABCDEF'
"""
def stringTobytes(bs):
return bytes(bs, encoding='utf8')
- bytes转字符串
'''
eg:
b'0123456789ABCDEF0123456789ABCDEF'
'0123456789ABCDEF0123456789ABCDEF'
'''
def bytesToString(bs):
return bytes.decode(bs, encoding='utf8')
- 十六进制字符串转bytes
'''
eg:
'01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF'
b'\x01#Eg\x89\xab\xcd\xef\x01#Eg\x89\xab\xcd\xef'
'''
def hexStringTobytes(bs):
bsr = bs.replace(" ", "")
return bytes.fromhex(bsr)
# return a2b_hex(str)
- bytes转十六进制字符串
'''
eg:
b'\x01#Eg\x89\xab\xcd\xef\x01#Eg\x89\xab\xcd\xef'
'01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF'
'''
def bytesToHexString(bs):
return ''.join(['%02X ' % b for b in bs])
数字类型
具体可以分为以下四种
- 整型
int
- 长整型
long integers
- 浮点型
float
- 复数
complex
:由实数和虚数组成,可以用a + bj
或complex(a, b)
表示,复数的实部a和虚部b都是浮点型
数学函数math、cmath
math提供了许多对浮点数的数学运算函数
cmath更多是针对复数的运算
函数 | 描述 |
---|---|
abs(x) | 返回数字的整型绝对值(内置函数) |
fabs(x) | 返回数字的浮点型绝对值(math) |
ceil(x) | 向上取整 |
cmp(x, y) | x<y返回-1,x=y返回0,x>y返回1 |
exp(x) | 返回e的x次幂,如math,exp(1) 返回2.71828… |
数据类型转换
描述 | 函数 |
---|---|
int(x) | 将x转换为整数 |
long(x) | 将x转换为长整数 |
float(x) | 将x转换为浮点数 |
complex(real) | 创建一个复数 |
str(x) | 将对象x转换为字符串 |
repr(x) | 将对象x转换为表达式字符串,即会在字符串外面再包裹一层引号,这在使用eval() 时体现了repr() 的特殊效果。 |
eval(x) | 计算再字符串中的有效python表达式,并返回一个对象,目前常用于字符串转字典 |
tuple(s) | 将序列s转换为一个元组 |
list(s) | 将序列s转换为一个列表 |
set(x) | 转换为可变集合 |
dict(d) | 创建一个字典,d必须是一个序列(key, value) 元组 |
frozenset(s) | 转换为不可变集合 |
chr(x) | 将一个整数转换为一个字符 |
unichr(x) | 将一个整数转换为Unicode字符 |
ord(x) | 将一个字符转换为它的整数值 |
hex(x) | 将一个整数转换为16进制字符串 |
oct(x) | 将一个整数转换为一个8进制字符串 |
运算符
运算符分类
运算符类型 | 运算符 |
---|---|
算术运算符 | ①加+ ;②减- ;③乘* ;④除/ ;⑤取余% ;⑥幂** ;⑦向下取整除// |
比较运算符 | ①等于== ;②不等于!= ;③大于> ;④小于< ;⑤大于等于>= ;⑥小于等于<= |
赋值运算符 | ①赋值= ;②加法赋值+= ;③减法赋值-= ;④乘法赋值*= ;⑤除法赋值/= ;⑥取模赋值%= ;⑦幂赋值**= ;⑧取整除赋值//= |
位运算符 | ①按位与& :参与运算的两个值,如果相应位都是1则该位为1否则为0;②按位或` |
逻辑运算符 | ① 布尔与and :左右两边都为真时结果为真,只有左侧的为真才会执行右侧的表达式;②布尔或or :左右两边只要有一个为真时结果为真;③布尔非not :取反 |
成员运算符 | ①在…之中in :能够在指定的序列当中找到该值为真,否则为假;②不在…之中not in :在指定序列当中找不到该值为真,否则为假 |
身份运算符 | ①判断两个标识符是不是引用自同一个对象is ;②判断两个标识符是不是引用自不同对象is not |
优先级
由高到低,同一类型越靠前优先级越高
- 指数:
**
- 按位翻转、一元加号和减号:
~
、+@
、-@
- 乘、除、取模和取整除:
*
、/
、%
、//
- 加、减:
+
、-
- 左移、右移:
>>
、<<
- 位与:
&
- 位或:
^
、|
- 比较:
<=
、>=
、<
、>
- 等于:
==
、!=
- 赋值:
=
、%=
、/=
、//=
、-=
、+=
、*=
、**=
- 身份:
is
、is not
- 成员:
in
、not in
- 逻辑:
not
、and
、or
- 匿名函数:lambda
注意点
==
和is
是不同的,前者比较的是两者的值,而后者比较的是两者的地址。在使用它们进行比较时需要慎重。- 赋值列表时有两种方式:①
a = b
;②a = b[:]
。两者结果一致,但区别在于前者是传递引用,仍然是同一个对象;后者是拷贝,创建了新的对象
流程控制
在使用流程控制前,需要提前了解的是:在python中,任何非0和非空(null)的布尔值都为True,与之相反的0和空为False。
条件判断
在使用流程控制时,可以配合逻辑运算符使用:
a = 0
b = 1
# 以下程序不会报错
if a > 0 and b / a > 2:
print('yes')
else:
print('no')
# 以下程序会报错
if (b/a > 2):
...
在python中没有switch,但可以手动实现:
def zero():
return '0'
def one():
return '1'
...
def num2str(arg):
# 使用字典映射
switcher = {
0: zero,
1: one,
2: lambda: "three"
}
func = switcher.get(arg, lambda:"nothing")
return func
num2str(0)
简单的条件判断可以缩写至一行内:
a = [1, 2, 3]
b = a if len(a) != 0 else ''
循环
循环种类:
- for
- while
- 嵌套
循环控制:
- break:跳出最深层循环
- continue:跳过本次循环,执行下一次循环
- pass:空语句,使流程控制的结构完整
while注意点
- 循环可以在不满足条件时执行else语句,即循环不是通过break退出时,如:
a = 0
while a < 5:
a += 1
print(a)
else:
print(a)
- 类似于if语句,当循环体中只有一条语句可以缩写至一行:
flag = 1
while (flag): print("flag is true")
for注意点
- 通过序列索引迭代:
fruits = ['banana', 'apple', 'mango']
for index in range(len(fruits)):
print(f'下标:{index},值为:{fruits[index]}')
- for循环与while循环一样可以使用else语句,同样是在循环正常执行完(非break跳出而中断)的情况下使用,while…else也是。
- for循环可以结合
enumerate()
内置函数使用,该函数会将一个可遍历对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标:如下所示
sequence = [12, 34, 56, 66]
for index, item in enumerate(sequence):
print(index, item)
# 输出如下
'''
0 12
1 34
2 56
3 66
'''
函数
参数传递
- 位置实参:根据位置传递
- 关键字实参:根据形参的名称传递
- 在函数调用过程中,进行参数的传递:如果是不可变对象,在函数体的修改不会影响实参的值,如字符串;如果是可变对象,在函数体内的修改会影响到实参的值,如列表
- 如果函数的参数有默认值,在传递参数时新传递的参数会替代默认参数,如不传递则会使用默认参数
- 如果不确定需要传递参数的个数,则可以使用可变的位置参数或可变的关键字参数,分别使用
*
和**
定义,结果分别为元组和字典,但它们都只能定义一个,且如果同时使用可变的位置参数和可变的关键字参数,要求个数可变的位置形参放在个数可变的关键字形参之前,它们又称为不定长参数
# 可变的位置参数
def fun(*args):
# 可变的关键字参数
def fun(**args):
- 调用时将序列中的每个元素都转换为位置实参:使用
*
- 调用时将序列中的每个元素都转换为关键字实参:使用
**
(如字典) - 定义时使用
*
分隔形参的作用:规定*后面的形参只能使用关键字传参的方式
def fun(a,b,*,c,d):
print(a,b,c,d)
fun(10,20,30,40) # 报错:*号之后的形参需要使用关键字参数传递
fun(10,20,c=30,d=40)
fun(a=10,b=20,c=30,d=40)
函数定义时形参的顺序问题
def fun(a,b,*,c,d,**args):
pass
def fun1(*args,**args2):
pass
def fun2(a,b=10,*args,**args2):
pass
返回值
- 如果没有返回值(函数执行完之后不需要给调用处提供数据):return可以省略不写
- 函数的返回值,如果是单个,直接返回返回值类型的返回值
- 函数的返回值如果是多个,返回的结果是元组
变量的作用域
- 局部变量:函数内定义并使用的变量,仅在函数内部可用,局部变量使用global声明则变为全局变量
- 全局变量:函数外定义
递归
阶乘
def fac(n):
if n == 1:
return 1
else:
return n * fac(n-1)
斐波那契数列
def fib(n):
if n == 1:
return 1
elif n == 2:
return 1
else:
return fib(n-1)+fib(n-2)
# 输出这个数列的前六位
for i in range(1,7)
print(fib(i))
"""
range() :创建一个整数列表,一般在for循环中使用
语法:range(start, stop [,step])
start 默认为0,为0时可省略
stop 计数到stop结束,但不包括stop
step 步长默认为1,为1时可省略
"""
常用内置函数
多个值分割转为整形
a,b,c,d = map(int,input('输入4个值,用空格分隔').split())
round()
会像最靠近的偶数取整
print(round(3.5)) # 4
print(round(4.5)) # 4
math.ceil()向上取整
按需导入模块中的函数
- from 模块 import 函数
导入模块中的所有函数
- from 模块 import *
python使用cmd指令
import os
Dir(os)
查看os有什么函数help(os.system)
查看os.system的具体说明- 如:
os.system('cls')
清屏
range()
range(start, stop[, step])
- start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
- stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
- step:步长,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)
判断数据类型
type()
type(obj)
输出该变量的数据类型
instance()
instance(x, type)
,如果x是type类型的话输出True,否则输出False
结论:在判断数据类型时需要使用instance()
因为它可以精确的判断出实例是否是某类或者其子类,而如果类的继承方式不是使用新式类的继承方式,将不能保证正确的输出。而造成这种结果的原因是type是值比较,而instance是地址比较。
魔法方法
-
以
__
开头和结尾的方法称为魔法方法
如__init__(self[,……])
ps:相当于其他语言的构造方法 -
__init__
方法不能有任何return
-
__new__(cls[,……])
:实例化对象时调用的第一个方法,一般不需要去重写它,但当继承不可变类型但却又需要修改时它就显得尤为重要
class CapStr(str):
def __new__(cls, string):
string = string.upper()
return str.__new__(cls, string)
'''
将传入的内容转化为大写
步骤:
1.传入字符串
2.调用__new__方法
3.将传入的string变为大写
4.将变化后的string交给str基类中的__new__方法处理,生成一个字符串
'''
__del__
:不管是手动调用del还是由Python自动回收都会触发__del__
方法执行,ps:del引用并不会触发del
魔法方法 | 作用 |
---|---|
__add__(self,other) | 定义加法的行为:+ |
__sub__(self,other) | 定义减法的行为:- |
__mul__(self,other) | 定义乘法的行为:* |
__truediv__(self,other) | 定义除法的行为:/ |
__floordiv__(self,other) | 定义整数除法的行为:// |
__mod__(self,other) | 定义取模算法的行为:% |
__divmod__(self,other) | 定义当被divmod()调用时的行为 |
__pow__(self,other[,modulo]) | 定义当被power()调用或**运算时的作用 |
__lshift__(self,other) | 定义按位左移位的行为:<< |
__rshift__(self,other) | 定义按位右移位的行为:>> |
__and__(self,other) | 定义按位与操作的行为:& |
__xor__(self,other) | 定义按位异或操作的行为:^ |
__or__(self,other) | 定义按位或操作的行为:` |
简单定制
基本要求:
- 定制一个计时器的类
- start和stop方法代表启动计时和停止计时
- 假设计时器对象t1,print(t1)和直接调用t1均显示结果
- 当计时器未启动或已经停止计时,调用stop方法会给予温馨提示
- 两个计时器对象可以进行相加:t1+t2
- 只能使用提供的有限资源完成:
- (1)使用
time
模块的localtime
方法获取时间 - (2)
time.localtime
返回struct_time
的时间格式 - (3)重写
__str__
和__repr__
实现在print和直接调用时显示结果
import time
class MyTimer:
def __init__(self):
self.unit = ['年', '月', '日', '时', '分', '秒']
self.prompt = '未开始计时'
self.lasted = []
self.startTime = 0
self.stopTime = 0
def __str__(self):
return self.prompt
__repr__ = __str__
def __add__(self, other):
prompt = '总共运行了'
result = []
for index in range(6):
result.append(self.lasted[index] + other.lasted[index])
if result[index]:
prompt += (str(result[index]) + self.unit[index])
return prompt
def start(self):
self.startTime = time.localtime()
self.prompt = '提示:请先调用stop() 停止计时'
print('开始计时')
def stop(self):
if not self.startTime:
self.prompt = '提示:请先调用start() 开始计时'
else:
self.stopTime = time.localtime()
self._calc()
def _calc(self):
self.lasted = []
self.prompt = '共运行了'
for index in range(6):
self.lasted.append(self.stopTime[index] - self.startTime[index])
if self.lasted[index]:
self.prompt += (str(self.lasted[index]) + self.unit[index])
self.startTime = 0
self.stopTime = 0
属性访问
__getattr__(self, name)
:定义当用户试图获取一个不存在的属性时的行为__getattribute__(self, name)
:定义当该类的属性被访问时的行为__setattr__(self, name, value)
:定义当一个属性被设置时的行为__delattr__(self, name)
:定义当一个属性被删除时的行为
# 创建一个矩形类,当设置属性为square时设置长宽相同并计算面积
class Rectangle:
def __init__(self, w=0, h=0):
self.w = w
self.h = h
def __setattr__(self, name, value):
if name == 'square':
self.w = value
self.h = value
print('this is a square')
else:
super().__setattr__(name, value)
# self.__dict__[name] = value
def getArea(self):
return self.w * self.h
property原理
描述符:将某种特殊类型的类的实例指派给另一个类的属性
__get__(self, instance, owner)
:用于访问属性,返回属性的值__set__(self, instance, value)
:将在属性分配操作中调用,不返回任何内容__delete__(self, instance)
:控制删除操作,不返回任何内容
# 案例:摄氏度和华氏度转换
class Celsius:
def __init__(self, value=26.0):
self.value = value
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
self.value = float(value)
class Fahrenheit:
def __get__(self, instance, owner):
return instance.cel * 1.8 + 32
def __set__(self, instance, value):
instance.cel = (float(value) - 32) / 1.8
class Temperature:
cel = Celsius()
fah = Fahrenheit()
temp = Temperature()
temp.cel = 30 # 赋值摄氏度
print(temp.fah) # =>86
temp.fah = 100
print(temp.cel) # =>37.77777777777778
协议
protocols(协议):与其他语言的接口类似,规定哪些方法必须定义。然而在Python中的协议并不是很正式,实际上更像是指南
DuckTyping:当看到一只鸟走起来像鸭子,游泳起来像鸭子,叫也像鸭子,那么这只鸟就可以被称为鸭子
定制类型的协议
- 如果希望定制的容器是不可变的话,只需要定义
__len__()
和__getitem__()
方法 - 如果希望定制的容器是可变的,除了
__len__()
和__getitem__()
方法,还需要定义__setitem__()
和__delitem__()
方法
"""不可变自定义列表,记录列表中每个元素被访问的次数"""
class CountList:
def __init__(self, *args):
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)), 0)
def __len__(self):
return len(self.values)
def __getitem__(self, item):
self.count[item] += 1
return self.values[item]
c1 = CountList(1,2,3,4,5)
c2 = CountList(2,4,5,6,10)
print(c1[1]) # =>2
print(c2[1]) # =>4
print(c1[1] + c2[1]) # =>6
print(c1.count) # =>{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c1[1]) # =>2
print(c1.count) # =>{0: 0, 1: 3, 2: 0, 3: 0, 4: 0}
迭代器(iter)
- for循环
iter()
:创建一个迭代器对象;它自带一个魔法方法:__iter__()
,返回它本身next()
:输出下一个值,如果没有下一个值,则抛出StopIteration
异常;它自带一个魔法方法:__next__()
,规定了迭代器的规则
string = "hello Python"
it = iter(string)
while True:
try:
each = next(it)
except StopIteration:
break
print(each)
# 迭代器魔法方法的使用
class Fibs:
def __init__(self, n=10):
self.a = a
self.b = b
self.n = n
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > self.n
raise StopIteration # 超过10就手动抛异常
return self.a
fibs = Fibs(100) # 迭代值为100的斐波那契数列
for each in fibs:
print(each) # 输出1~100中的斐波那契数列
生成器(yield)
- 协同程序:可以运行的独立函数调用,函数可以暂停或者挂起,在需要的时候从程序离开的地方继续或重新开始
- 是一个特殊的迭代器
BUG
SyntaxError
语法错误indexError
索引越界- indentationError:缩进错误
- 思路不清 =》print打印输出的内容确认是否是需要的类型;注释部分代码排查错误
异常处理
出现例外情况
- 异常处理try……except(相等于Java的try catch)
- 多个except结构:捕获异常的顺序按照先子类后父类的顺序,为了避免遗漏可能出现的异常,可以在最后增加BaseException
- try……except……else 如果try块中没有抛出异常,则执行else块,如果抛出异常则执行except块
- try……except……else……finally finally块无论是否发生异常都会被执行,常用于释放try块中申请的资源
常见的异常类型
异常类型 | 描述 |
---|---|
ZeroDivisionError | 除(或取摸)零(所有数据类型) |
IndexError | 序列中没有此索引 |
KeyError | 映射中没有这个键 |
NameError | 未声明/初始化对象(没有属性) |
SyntaxError | 语法错误 |
ValueError | 传入无效参数 |
URLError | urllib库的error模块 |
HTTPError | 是URLError的子类;code:返回状态码;reason:返回错误原因;headers:返回请求头 |
![]() |
手动抛异常
Python raise用法
raise
raise [exceptionName [(reason)]]
其中,用 [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。如果可选参数全部省略,则 raise 会把当前错误原样抛出;如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息。
也就是说,raise 语句有如下三种常用的用法:
- raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
- raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。
- raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
- 在使用 raise 语句时可以不带参数
try:
a = input("输入一个数:")
if(not a.isdigit()):
raise ValueError("a 必须是数字")
except ValueError as e:
print("引发异常:",repr(e))
raise
程序执行结果为:
输入一个数:a
引发异常: ValueError('a 必须是数字',)
Traceback (most recent call last):
File "D:\python3.6\1.py", line 4, in <module>
raise ValueError("a 必须是数字")
ValueError: a 必须是数字
这里重点关注位于 except 块中的 raise,由于在其之前我们已经手动引发了 ValueError 异常,因此这里当再使用 raise 语句时,它会再次引发一次。
当在没有引发过异常的程序使用无参的 raise 语句时,它默认引发的是 RuntimeError 异常。例如:
try:
a = input("输入一个数:")
if(not a.isdigit()):
raise
except RuntimeError as e:
print("引发异常:",repr(e))
程序执行结果为:
输入一个数:a
引发异常: RuntimeError('No active exception to reraise',)
Trackback模块
import traceback
try:
print('------------')
num = 10 / 0
except:
traceback.print_exc()
# 会打印出异常的信息,作用是更方便后续存储为log日志
类、对象
class Student:
native_pace = '福建' # 成员变量(类属性),被该类的所有对象共享
def __init__(self, name, age):
self.name = name # self.name 为实体属性,将局部变量赋值给实体属性
self.age = age
# 实例方法
def eat(self):
pass
# 静态方法 , 使用类名直接访问
@staticmethod
def method():
pass # 静态方法不需要self,使用staticmethod静态修饰符修饰
# 类方法 , 使用类名可以直接访问
@classmethod
def cm(cls):
pass # 类方法需要传递cls参数,使用classmethod修饰符修饰
使用类中的方法:
stu = Student('张三', 20)
stu.eat() # 对象名.方法名()
Student.eat(stu) # 与上一行代码功能相同,都是调用了同一个方法
# 不同的是传递的参数形式不同,实际上传入的位置是self
# 类名.方法名(实例对象)
# 类方法和静态方法的使用
Student.cm()
Student.method()
动态绑定属性和方法
类可以创建N个该类的实例对象,每个实例对象的属性不同
stu = Student('张三',20)
stu.sex = '女' # 动态绑定属性
def show(): # 类外面的函数
pass
stu.show = show # 动态绑定方法
stu.show()
面向对象
面向对象编程:OOP
面向过程:注重每一个步骤
面向对象:注重结果
类的组成
- 名称
- 属性
- 方法
类是对象的抽象,对象是类的实例。
类分为:经典类 和 新式类。
类的创建:
class ClassName:
# 类名后不管加不加括号`()`都会继承元类`type`
pass
cl1 = ClassName()
类本身也是对象。
对象的属性
查看对象中的所有属性:
对象.dict : cl1.__dict__
增
对象.属性名 : cl1.att1 = "属性1"
类对象.属性名 : ClassName.att2 = "类对象属性"
删
del 对象.属性:del cl1.att1
del 类对象.属性: del ClassName.att
改
非可变类型等同于重新赋值 (内存地址被改变)。
可变类型(如列表)通过列表的方法修改 (内存地址不变)。
类对象同理
查
通过对象去访问对象的属性: print(cl1.att1)
如果在对象中找到了相应的属性,则优先使用,
如果没有找到相应的属性,则会通过__class__
到对象的父类当中去查找;故而如果可以中途改变__class__
的指向,改变该对象的父类。
所以想要查找类对象的属性,既可以通过对象去访问父类的方式(前提是对象中没有这个属性,是由父类继承而来),也可以通过 类对象.属性名 print(ClassName.att)
的方式查找。
可以通过id(对象.属性名)
的方式验证属性的内存地址的方式验证。
总结
以上通过 对象.属性名的方式去增删改查,实际上都是通过对象的__dict__
属性进行操作。
默认情况下类对象的__dict__
是只读的,当后续可以通过其他函数进行操作如(setattr)。
对象在正常情况下可以肆无忌惮的添加属性,这就降低了类对象对其的约束,故而可以在类对象中添加__slots__
属性约定对象可以添加的属性如__slots__ = ["age"]
,之后对象如果添加不在约定范围内的属性则会报属性不存在
对象的方法
方法的划分:
-
实例方法
默认第一个参数接收一个实例对象
-
类方法
默认第一个参数接收一个类对象
-
静态方法
没有默认参数
class Person:
def test1(self):
# 实例方法
pass
@classmethod
def test2(cls):
# 类方法
pass
@staticmethod
def test3():
# 静态方法
pass
ps:直接通过类名去访问实例方法,且没有传递参数会报错:缺少实例对象。
方法的调用:
-
实例方法
标准调用:使用实例去调用实例方法,不需要手动传默认参数
其他调用:1使用类调用 2找到函数本身调用(因为对象中的方法实际上也是位于
__dict__
的键值对的值中) -
类方法
标准调用:使用类去调类方法
其他调用:1.使用实例调用(实例会被忽略,实例对应的类不会被忽略)2.使用子类调用父类的类方法。
封装
- 提高程序的安全性
- 如果不希望在类对象外部访问,前面加两个** _**,但仍然可以通过dir()查询到该方法并使用(如在类中定义一个属性__age = 20,通过实例对象.__age无法使用该属性,但通过查询dir(实例对象);可以得知它的属性名被更改为_Student__age,使用实例对象._Student__age依然可以使用)
继承
- 提高复用性
- 如果一个类没有继承任何类,则默认继承object
- python支持多继承
- 定义子类时,必须在其构造函数中调用父类的构造函数
class Person: # 默认继承object
def __init__(self,name,age):
self.name = name
self.age = age
def info(self):
print(self.name, self.age)
class Student(Person):
def __init__(self,name,age,stu_no):
super().__init__(name,age)
self.stu_no = stu_no
class Teacher(Person):
def __init__(self,name,age,techOfYear):
super().__init(name,age)
self.techOfYear = techOfYear
stu = Student('张三', 20, '1001')
teacher = Teacher('李四', 30, 5)
stu.info() # out:张三 20
teacher.info() # out:李四 30
# 该方法都是从Person类继承过来的
方法重写
class Student(Person):
def __init__(self,name,age,stu_no):
super().__init__(name,age)
self.stu_no = stu_no
# 重写Person类中的info方法
def info(self):
super().info() # 仍然需要父类方法中的内容
print(self.stu_no)
object类
- object类是所有类的父类,因此所有类都有object类的属性和方法
- 内置函数dir() 可以查看指定对象所有的属性
- object有一个
__str__
方法,用于返回一个对于对象的描述,对应内置函数str()经常用于print()方法,帮助用户查看对象的信息,所以用户经常会将__str__()
重写
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print('姓名:{0},年龄{1}'.format(self.name,self.age))
def __str__(self):
return '姓名:{0},年龄{1}'.format(self.name,self.age)
o = object()
p = Person('jack', 20)
print(dir(o))
print(dir(p))
print(p) # out:姓名:jacl,年龄20
多态
- 多态即多种形态
- 指的是:即使不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用的类型,动态决定调用哪个对象中的方法
静态语言和动态语言关于多态的区别
静态语言实现多态的三个必要条件
- 继承
- 方法重写
- 父类引用指向子类对象
动态语言的多态崇尚鸭子类型当看到一只鸟走起来像鸭子、游泳像鸭子、吃像鸭子,那么这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象到底是什么类星星,到底是不是鸭子,只关心对象的行为。
特殊属性和特殊方法
名称 | 描述 | |
---|---|---|
特殊属性 | __dict__ | 获得类对象或实例对象所绑定的所有属性和方法的字典 |
特殊方法 | __len__() | 通过重写__len__() 方法,让内置函数__len__() 的参数可以是自定义类型 |
__add__() | 通过重写__add__() 方法,可使用自定义对象具有”+“功能 | |
__new__() | 用于创建对象 | |
__init__() | 对创建的对象进行初始化 |
"""
实现两个对象相加的操作
"""
class Student:
def __init__(self,name):
self.name = name
def __add__(self, other):
return self.name + other.name
def __len__(self):
return len(self.name) # 调用此方法返回name长度
stu1 = Student('张三')
stu2 = Student('李四')
s = stu1 + stu2
print(s) # out:张三李四
类的赋值与浅拷贝
变量的赋值操作:
- 只是形成了两个变量,实际上还是指向同一个对象
浅拷贝:
- python拷贝一般是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象
class Cpu:
pass
class Disk:
pass
class Computer:
def __init__(self,cpu,disk):
self.cpu = cpu
self.disk = disk
"""
1.变量的赋值
"""
cpu1 = Cpu()
cpu2 = cpu1
print(cpu1)
print(cpu2) # 相等
"""
2.类的浅拷贝
"""
disk = Disk() # 创建硬盘类对象
computer = Computer(cpu1, disk) # 创建一个计算机类的对象
import copy
computer2 = copy.copy(computer)
print(computer, computer.cpu, computer.disk)
print(computer2, computer2.cpu, computer2.disk) # 输出结果仅computer和computer2不同,其他两项相同,证明在浅拷贝过后,子对象不变
深拷贝:
- 使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象不相同
computer3 = copy.deepcopy(computer)
print(computer, computer.cpu, computer.disk)
print(computer3, computer3.cpu, computer3.disk) # 输出结果都不相同
补充
元类 -> type
创建类对象
- 通过关键字
class
- 通过元类:
class_name = type("ClassName",(父类),__dict__)
类对象的创建流程及方式:
- 检测类中是否有明确的
__metaclass__
属性 - 没有就到父类中查找是否存在
__metaclass__
属性 - 没有就到模块(当前的py文件)中查找是否有
__metaclass__
属性 - 都没有就通过
type
创建这个类对象
类的描述
class ClassName:
"""
在此处输入类的描述,作用,属性
Attributes:
属性的描述
"""
def test(self, param1, param2):
"""
在此处输入方法的描述
:param param1: 参数的含义, 类型, 是否有默认值
:param param2: ----
:return: 返回值的含义, 类型
"""
print(self, param1, param2)
help(ClassName) # 通过help可以生成文档
生成项目文档:
使用内置模块:pydoc
私有化属性
python中只有伪私有化,即通过下划线来规定私有属性。
公有属性 | 单下划线私有属性 | 双下划线私有属性 |
---|---|---|
在所有区域都能被访问 | 在类的内部和子类的内部可以被访问,其他区域会警告但仍可被访问 | 只有类内部能访问,其他均不能 |
注意:私有属性可以通过在被访问的文件中添加
__all__
,让其他模块访问私有属性且不会警告和报错。
私有属性的实现机制:名字重整(Name Mangling)
应用场景:
- 数据保护
- 数据过滤
补充:xxx_这样的变量名是为了与系统变量做区分如id_,__xxx__则是系统内置的属性或方法
只读属性
方案1
- 私有化:通过双下划线方式实现
- 部分公开: 单独定义一个实例方法用于返回属性
- 优化: 通过修饰器
property
以使用属性的方式使用方法
class Person(object):
def __init__(self):
slef.__age = 18
@property
def age(self):
return self.__age
p = Person()
print(p.age) # 可以得到__age的值
# p.age = xxx # 不能修改,会报错没有这个属性
装饰器property
property的两种使用方式
class C(object):
def getx(self):return self._x
def setx(self, value):self._x = value
def delx(self): del self._x
x = property(getx, setx, delx, f"x属性")
class D(object):
@property
def x(self):
# "x属性"
return self._x
@x.setter
def x(self, value):
self_x = value
@x.deleter
def x(self):
del self._x
补充: 经典类和新式类
- 经典类:没有继承object
- 新式类:继承了object
在python2.x中,没有显式的继承object则这个类是经典类,必须显式继承(写在括号里)才是新式类,而到了python3.x中,默认情况下隐式继承object,但仍建议显示继承
经典类中的property与新式类不同,经典类不能使用除property的getter以外的修饰方法
模块
- Modules
- 一个 .py 文件就是一个模块
- 可以包含若干个函数、类、变量
- 优点:方便其他程序和脚本的导入使用;避免函数名和变量名冲突;提高代码的可维护性;提高代码的可重用性
查看模块内的内容
id()
查看内存地址type()
类型dir()
查看模块内都有什么
以主程序形式运行
if __name__ == '__main__':
下的代码块
只有通过自身执行时才会输出的内容,如果通过其他文件进行导入使用则不会执行
包
- 分层次的目录结构
- 目的是整合功能相近的模块
- 作用是使代码规范;避免模块名称冲突
- 包与目录的区别:包含
__init__.py
的目录称为包;目录里通常不包含__init.py
文件 - 导入
import 包名
只能导入包、模块,使用from……import……
能导入包、模块、函数、变量
常用内置模块
第三方模块的安装使用
- 在线安装:
pip install 模块名
- 验证安装:
import 模块
常用模块的使用
时间模块time和datetime
import time
或import datetime
本地时间:time.localtime(time.time())
格式化时间:time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
反格式化时间:time.strptime(时间字符串, 时间格式)
延迟:time.sleep(秒)
datetime
模块相当于对time
进行了封装,常用的有:datetime.datetime
和datetime.timedalta
,具体的方法如下:
datetime.year
datetime.month
datetime.day
datetime.hour
datetime.minute
datetime.second
datetime.tzinfo
时区datetime.date()
返回date对象datetime.time()
返回time对象datetime.timetuple
返回time.struct_time
对象datetime.strftime()
和datetime.strptime()
datetime
类本身也有些方法如:datetime.today()
/datetime.now()
等
文件操作
编码格式
- 常见的字符编码格式
- python的解释器使用的是Unicode(内存)
.py
文件在磁盘上使用的是UTF-8(外存)
- 在开头注释
#encoding=gbk
的方式可以改变文档的编码格式 - 不同编码格式的文档大小不同
读取键盘输入
raw_input("请输入:")
:获取用户输入的任意字符串input("请输入:")
文件的读写原理(IO)
- 队列:先进先出
- 内置函数open()创建文件对象。格式:
file = open(filename [,mode. encoding])
。 file
:被创建的文件对象;open
:创建文件对象的函数;filename
:要创建或打开的文件名称;mode
:打开模式默认为只读'r'
;encoding:默认文本文件.txt
中字符的编写格式为gbk
常用文件打开模式
文件对象的常用方法
WITH语句(上下文管理器)
with语句可以自动管理上下文资源,不论什么原因跳出with块都可以保证文件正确的关闭以达到释放资源的目的
with open('logo.png', 'rb') as src_file
- 可以将with语句分为两部分:with之后as之前
- as之前的内容称为上下文表达式,结果为上下文管理器,同时会创建一个运行时上下文
- 相当于自动实现了
__enter__()
和__exit__()
方法 - 无论语句内是否存在错误都将在执行完之后自动释放资源
目录操作
os模块
- 是python内置的与操作系统功能和文件系统相关的模块,该模块中的语句的执行结果通常与操作系统有关,在不同的系统上运行,得到的结果可能不同
- 该模块与
os.path
模块用于对目录或文件进行操作
os.path模块操作目录相关函数
"""
案例:打印出所有当前目录下的.py文件
"""
import os
path = os.getcwd()
lst = os.listdir(path)
for filename in lst:
if filename.endswith('.py'):
print(filename)
"""
案例2:打印当前目录(包含子目录)下的所有文件
"""
import os
path = os.getcwd()
lst_files = os.walk(path) #os.walk 可以遍历指定目录下的所有文件及目录,类似递归操作
for dirpath, dirname, filename in lst_files:
print(dirpath) # 路径
print(dirname) # 文件夹
print(filename) # 文件
for dir in dirname:
print(os.path.join(dirpath, dir)) # 拼接操作,输出当前目录下所有子路径
for file in filename:
print(os.path.join(dirpath, file)) # 输出所有文件的路径
爬虫
python如何访问互联网
- URL
- lib
- URL+lib = URLLIB
import urllib.request
res = urllib.request.urlopen("http://wwww.fishc.com")
html = res.read()
print(html.decode("utf-8"))
案例:爬取有道翻译接口翻译
import urllib.request as ur
import urllib.parse as up
import json
# 方法1:添加访问延迟
import time
while True:
content = input('输入需要翻译的内容:')
if content == 'q!':
break
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
# 在此基础上增加上防止被当作频繁访问的非正常用户过滤的头文件
head = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66 '}
data = {'i': content, 'from': 'AUTO', 'to': 'AUTO', 'smartresult': 'dict', 'client': 'fanyideskweb',
'salt': '16100780760685', 'sign': '98955f990c05972ae4ae00da51c4e60e', 'lts': '1610078076068',
'bv': 'e352c26cfcd0c5f4e08ab85e750e759a', 'doctype': 'json', 'version': '2.1', 'eyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'}
data = up.urlencode(data).encode('utf-8')
res = ur.urlopen(url, data)
html = res.read().decode('utf-8')
target = json.loads(html)
print('翻译结果:%s' % (target['translateResult'][0][0]['tgt']))
time.sleep(3)
ps:通过修改头文件使得访问更接近于正常人
- 通过
Request
的headers
参数修改 - 通过
Request.add_header()
方法修改
ps2:防止被屏蔽
- 增加延迟
- 使用代理
代理
步骤:
- 参数是一个字典
{'类型':'代理ip:端口号'}
proxy_support = urllib.request.ProxyHandler({})
- 定制、创建一个opener
opener = urllib.request.build_opener(proxy_support)
- 安装opener
urllib.request.install_opener(opener)
- 调用opener
opener.open(url)
"""
案例:使用代理在ip查询网站查询自己的ip
"""
import urllib.request as ur
import random
url = 'http://www.whatismyip.com.tw'
ipList = ['119.6.114.73:81', '183.203.208.166:8118', '111.1.32.28:81']
proxy_support = ur.ProxyHandler({'http':random.choice(ipList)})
opener = ur.build_opener(proxy_support)
ur.install_opener(opener)
res = ur.urlopen(url)
html = res.read().decode('utf-8')
print(html)
正则
re
re.search()
import re
re.search(r'Fishc', 'I love Fishc.com')
# 可以用点代表任何除换行之外的字符
re.search(r'.', 'Fishc.com')
# 反斜杠点代表原字符
re.search(r'\.', 'Fishc.com')
# 匹配任何数字
re.search(r'\d', 'fish 123')
# 匹配多个数字
re.search(r'\d\d\d', 'fish 123')
# 匹配符合条件的字母
re.search(r'[aeiou]', 'love I') # =>o ,大小写有区分
# 匹配范围字母
re.search(r'[a-z]', 'love fishc1234')
# 匹配范围数字
re.search(r'[1-9]', '213123asdas')
# 匹配b字符3次,b超多3个则不返回任何结果
re.search(r'ab{3}c', 'abbbc')
# 匹配3到10次以内的b
re.search(r'ab{3,10}c', 'abbbbbc')
# 匹配范围0-255
re.search(r'[0-2]\d\d|2[0-4]\d|25[0-5]', '188')
# 匹配ip地址,可以用{}优化
res = re.search(r'([0-2]\d\d|2[0-4]\d|25[0-5])\.([0-2]\d\d|2[0-4]\d|25[0-5])\.([1-9]|\d[0-9]|[0-2]\d\d|2[0-4]\d|25[0-5])\.([1-9]|\d[0-9]|[0-2]\d\d|2[0-4]\d|25[0-5])','ip:192.168.1.1')
# 非贪婪模式。默认正则会开启贪婪模式即匹配尽可能多的字符,当?紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的,单独使用则意为匹配前面的子表达式零次或一次
s = '<html><title>test</title></html>'
re.search(r'<.+?>', s) #=><html>
re.search(r'<.+>', s) # =>返回整个字符
re.findall()
找到匹配的字符并打包为列表返回
re.compile()
将正则表达式转化为模式对象,预编译
拓展用法
import re
result = re.search(r' (\w+) (\w+)', 'I love fishc.com')
# \w 匹配包括下划线的任何单词字符
print(result) # => <re.Match object; span=(1, 12), match=' love fishc'>
print(result.group()) # => love fishc
print(result.group(1)) # => love
print(result.start()) # => 1
print(result.end()) # => 12
print(result.span()) # => (1,12)