Python面向对象
作者:王珂
邮箱:49186456@qq.com
文章目录
前言
本文主要介绍Python进阶语法,以便在日后的工作中查阅参考。
官网:
https://www.python.org/
一、面向对象
Python同时支持面向过程和面向对象。
面向对象的三大特性:
-
继承:子类可以继承父类的属性和方法
-
封装:将属性和方法封装在一起
-
多态:相同的函数在不同的场景下有不同的表现
1.1 类的定义
类的定义
class 类名: # 或者 class 类名()
def 类方法(self, […]) # self是调用该方法的对象
…
# 定义类
class User: # 或者 class User()
def eat(self):
print('Have breakfast')
# 创建对象
user = User()
# 调用对象方法
user.eat()
class 类名(object):
def 类方法(self, […]) # self是调用该方法的对象
…
class User(object):
pass
object是所有类的父类
self关键字:
-
表示调用该方法的类对象
-
在类的内部调用类的方法
class User: def breakfast(self): print('Have breakfast ') def eat(self): self.breakfast()
魔法方法
类中有一些有魔力特殊的方法,在特殊的情况(类对象被创建、打印、销毁时)下会被自动调用,它们被双下划线包围,如:魔法方法名()
-
无参______init______() 或 init(self)
创建对象时会自动调用该方法
class User: # 在创建对象时会被自动调用 def __init__(self): self.name = 'wk' self.weight = 124 # 使用 user = User() print(user.name)
-
有参______init______(self, 参数1, 参数2)
class User: # 在创建对象时会被自动调用 def __init__(self, name, weight): self.name = name self.weight = weight # 使用 user = User('wk', '124') print(user.name)
-
文本输出______str______()
当使用print()输出对象时,默认打印的是对象的内存地址;
如果实现了______str______(),print()就会调用该魔法方法。该方法必须有返回值。class User: def __str__(): return '我是User对象'
-
删除______del______()
当删除对象(如:del user)或文件执行结束后,默认会调用______del______()
class User: def __del__(): print('我被删除')
1.2 类的属性
1.2.1 对象属性
公有属性
在______init______()中定义属性
self.属性名
class User:
def __init__():
self.name = 'wk'
在类的外部添加属性
对象名.属性名 = 属性值
class User:
def breakfast(self):
print('Have breakfast ')
user = User()
# 在类的外部添加属性
user.name = 'wk'
私有属性
某些属性和方法不想被子类继承,需要将其定义为私有。通过__属性 或 __方法 定义
-
私有的属性或方法只能在类的内部使用,不能在类的外部使用
-
如果想在外部使用,必须通过为其定义get_xxx或set_xxx接口
# 私有属性
__私有属性名
class Father(object):
def __init__(self):
# 私有属性,父亲存款
self.__money = 10000
def get_money(self):
"""为私有属性__money定义的公共的get接口"""
return self.__money
1.2.2 类的属性
指类所拥有的属性,它被共享于整个类中
类名.属性名
class Washer:
count = 1
def wash(self):
print('正在洗衣服...')
washer1 = Washer()
print(washer1.count) # 1
washer2 = Washer()
print(washer2.count) # 1
Washer.count += 1
# 注意,如果这里是 washer2.count =+ 1,那么 washer1.count 值仍为1
# washer2.count += 1
print(washer1.count) # 2
print(washer2.count) # 2
-
类属性既可以被 类.属性名调用
-
类属性也可以被 对象名.属性名调用
1.3 类的方法
1.3.1 对象方法
公有方法
class User(object):
def run(self):
""" 公有方法 """
print('跑步')
私有方法
__私有属性方法名
class Father(object):
def __smash(self):
""" 私有方法 """
print('砸石头')
1.3.2 类的方法
类所拥有的方法,并需要使用装饰器@classmethod来标识,同时类方法的第一个参数必须是类对象,通常以cls做为变量名称
格式:
@classmethod
def 类方法名(cls)
class User(object):
type = '人'
@classmethod()
def eat(cls):
print(f'{cls.type}可以吃东西')
类方法中使用cls.属性名调用类属性
访问类方法
-
通过 类名.方法名 访问
-
通过 对象名.方法名 访问
1.3.2 静态方法
使用装饰器@staticmethod修饰的方法称为静态方法,且静态方法不需要多定义参数
@staticmethod
def 方法名:
class User(object):
@staticmethod()
def run():
print('跑')
访问静态方法
-
通过 类名.方法名 访问
-
通过 对象名.方法名 访问
1.4 类的继承
1.4.1 单继承
单继承就是一个子类只能继承自一个父类,不能继承多个类。这个子类会有具有父类的属性和方法。
语法:
class 子类名(父类名):
pass
注意:所有类默认继承object类,object类是所有类的基类。
父类
class Father(object):
def __init__(self):
self.gender = 'male'
def jump():
print('我会跳')
子类
class Son(Father):
""" 子类重写__init__()方法后需要显示在调用父类的__init__()方法 """
def __init__():
super().__init__()
pass
注意:如果在子类中重写了__init__()方法后需要显示在调用父类的__init__()方法,这点和Java不一样
调用
son = Son()
print(son.gender)
son.jump()
1.4.2 多继承
一个类同时继承多个父类,它可以同时拥有所有父类的属性和方法。
语法:
class Father(object):
pass
class Mother(object):
pass
继承注意事项
-
一个类继承多个父类,优先(从左到右)继承第一个类的属性和方法。
-
使用Son.______mro______查看属性的继承顺序
-
使用Son.mro()查看方法的继承属性
class Father(object):
def __init__(self):
self.gender = 'male'
def job(self):
return 'ploughing'
class Mother(object):
def __init__(self):
self.gender = 'female'
def work(self):
return 'cook dinner'
class Son(Father, Mother):
pass
son = Son()
print(f'属性的调用顺序是:{Son.__mro__}')
print(f'方法的调用顺序是:{Son.mro()}')
print('儿子的性别是:%s' % son.gender)
print(f'儿子的工作是:%s' % son.work())
属性的调用顺序是:(<class ‘main.Son’>, <class ‘main.Father’>, <class ‘main.Mother’>, <class ‘object’>)
方法的调用顺序是:[<class ‘main.Son’>, <class ‘main.Father’>, <class ‘main.Mother’>, <class ‘object’>]
儿子的性别是:male
儿子的工作是:cook dinner
1.4.3 子类重写父类
重写也叫覆盖,在子类中可以重写父类中同名的属性和方法
class Father(object):
def __init__(self):
self.name = '老王'
def work(self):
return 'ploughing'
class Mother(object):
def __init__(self):
self.name = '苏氏'
def work(self):
return 'cook dinner'
class Son(Father, Mother):
def __init__(self):
self.name = '小王'
def work(self):
return 'coding'
son = Son()
print('儿子的姓名是:%s' % son.name)
print(f'儿子的工作是:%s' % son.work())
儿子的姓名是:小王
儿子的工作是:coding
1.4.4子类调用父类
方式一
在子类中调用父类的方法,需要先调用父类的______init______(),然后再调用对应的方法
父类名.init(self)
父类名.父类方法名(self)
class Father(object):
def __init__(self):
print('我是父亲')
self.name = '老王'
def work(self):
return 'ploughing'
class Mother(object):
def __init__(self):
print('我是母亲')
self.name = '苏氏'
def work(self):
return 'cook dinner'
class Son(Father, Mother):
def __init__(self):
print('我是儿子')
self.name = '小王'
def work(self):
return 'coding'
def father_work(self):
Father.__init__(self)
return Father.work(self)
son = Son()
print('儿子的姓名是:%s' % son.name)
print(f'儿子的工作是:%s' % son.work())
print(f'我父亲的工作是:{son.father_work()}')
我是儿子
儿子的姓名是:小王
儿子的工作是:coding
我是父亲
我父亲的工作是:ploughing
方式二
在子类中调用父类的方法,使用super().父类的方法名(self)。但是super()方式只适用于单继承模式。
# 注意,只适用于单继承模式
def mother_work(self):
super().__init__(self)
super().work(self)f)
super()是按照mro资源表查找父类
1.5 多态
多态,指多种形态。比如:同样一个函数在不同的场景下有不同的形态
class Animal(object):
def run(self):
pass
class Dog(Animal):
def run(self):
print('狗在跑')
class Cat(Animal):
def run(self):
print('猫在跑')
def animal_run(animal: Animal):
animal.run()
if __name__ == '__main__':
dog = Dog()
animal_run(dog)
cat = Cat()
animal_run(cat)
多态的条件
-
有继承(定义父类,定义子类,子类继承父类)
-
方法重写(子类重写父类方法)
-
父类引用指向子类对象(子类对象传给父类对象调用者)
注意:只要父类做为方法参数,就容易发生多态
1.6 抽象类(接口)
抽象类:含有抽象方法的类叫做抽象类
抽象方法:方法体是空实现(pass)称之为抽象方法
-
父类用来确定有哪些方法(父类指定接口标准)
class Fighter(object): def __init__(self): pass def get_power(self): pass
-
具体的方法实现由子类来实现(子类实现接口标准)
class HeroFighter(Fighter): def __init__(self): self.name = 'HeroFighter' def get_power(self): return 60 class AdvHeroFighter(HeroFighter): def __init__(self): self.name = 'AdvHeroFighter' def get_power(self): return 80
二、网络编程
2.1 基本概念
IP
-
IPv4
4个字节,32位二进制数,分为4个部分,每个部分8位,用10进制表示
-
IPv6
6个字节
端口
-
系统端口范围:0~1023
-
动态端口号:1024~65535
协议
-
TCP
Transmission Control Protocl 控制传输协议,基于字节流的传输层协议
-
三次握手
TODO
-
四次挥手
TODO
-
特点:
-
面向连接
通信双方必须先建立好连接才能进行数据传输,数据传输完成之后,需要断开连接,以释放系统资源
-
可靠传输
都建立连接、传输可靠数据
2.2 Socket套接字
Socket(简称:套接字)是进程之间通信的一个工具。他描述了一个连接的一个端点,提供网络应用程序中所有用到的网络地址和端口信息
Python中Socket编程需要导入socket包
2.2.3 Socket服务端
创建Socket基本的服务端
分为以下步骤
- 创建socket对象
# AF_INET: 表示internet之间通讯
# SOCK_STREAM:表示使用TCP协议发送字节流
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- 绑定IP和端口
server_socket.bind(('IP地址', 端口))
- 端口监听
server_socket.listen()
- 接收连接
server_socket.accept()
- 接收数据
server_socket.recv(缓冲区大小)
- 发送数据
server_socket.send(数据)
- 关闭连接
conn.close()
server_socket.clost()
Socket对象
方法名 | 方法含义 |
---|---|
bind((host, port)) | 绑定地址元组(host, port)到套接字,host是字符串类型的主机地址,port是int类型的端口 |
listen(backlog) | 开始监听。backlog最大连接数据。最小为1,通常设为5,最大128 |
accept() | |
import socket
SERVER_IP = '0.0.0.0'
SERVER_PORT = 1024
# AF_INET: 表示internet之间通讯
# SOCK_STREAM:表示使用TCP协议发送字节流
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口后复用(服务端退出或中断后,端口不会立即释放,需要等待1~2分钟,设置端口复用后会立即释放)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
server_socket.bind((SERVER_IP, SERVER_PORT))
# server_socket变成被动套接字,专门用来接收客户端的连接
server_socket.listen(1)
# 被动套接字server_socket从linux内核的连接套接字栈中获取一个连接
conn_socket, client_address = server_socket.accept() # 阻塞方法
print(f'conn={conn_socket}, address={client_address}')
data = conn_socket.recv(1024).decode('utf-8') # 阻塞方法
if len(data) != 0:
print(f'服务端接收数据:{data}')
else:
print('客户端已断开')
send_msg = input()
conn_socket.send(send_msg.encode('utf-8'))
conn_socket.close()
server_socket.close()
注意:服务端程序异常中断后,端口号不会立即释放,大概需要等待1~2分钟,可通过更改端口号或者设置端口复用解决
2.2.4 Socket客户端
import socket
SERVER_IP = '127.0.0.1'
SERVER_PORT = 1024
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((SERVER_IP, SERVER_PORT)) # 阻塞方法,连接服务端
client_socket.send('您好啊'.encode('utf-8'))
recv_data = client_socket.recv(1024).decode('utf-8')
print(f'客户端接收到数据:{recv_data}')
client_socket.close()
方法名 | 方法含义 |
---|---|
connect((host, port)) | 应用程序建立连接(应用程序从linux内核中获取套接字) |
三、多任务编程
多任务是指在同一时间内,同时执行多个任务(给人感觉好像是同时执行)。例如:现在电脑安装的操作系统都是多任务操作系统,可以同时运行多个软件
多任务表现形式
-
并发:在一段时间内,交替执行任务(任务数 大于 CPU的核数)
-
并行:在一段时间内,同时一起执行多个任务(任务数 小于 CPU 的核数)
3.1 进程
进程是CPU资源分配的最小单位
一个程序运行后,至少有一个进程
Python中的多进程:先创建一个主进程,再由主进程创建子进程
创建进程
- 导入进程工具包
import multiprocessing
- 创建进程对象
子进程 = multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}
group: 参数未使用,始终为None
target: 表示调用对象,即子进程要执行的函数(回调函数入口地址)
name: 子进程的名字
args: 子进程要执行的函数的参数,以元组方式传参
kwargs: 子进程要执行的函数的参数,以字典方式传参
- 启动进程
进程对象.start()
示例
import multiprocessing
import time
def listening_music():
for i in range(10):
print('I am listening to music')
time.sleep(0.2)
def playing_football():
for i in range(10):
print('I am playing football')
time.sleep(0.1)
if __name__ == '__main__':
# 注意:多进程的代码必须写在 if main 中
music_process = multiprocessing.Process(group=None, target=listening_music, name='music')
football_process = multiprocessing.Process(group=None, target=playing_football, name='football')
t1 = time.time()
music_process.start() # 主进程等待子进程music_process执行完毕再往下执行
football_process.start() # 主进程等待子进程football_process执行完毕再往下执行
music_process.join()
football_process.join()
t2 = time.time()
print(f'总共耗时:{t2 - t1}')
子进程带函数参数
import multiprocessing
import time
def listening_music(username, music):
for i in range(10):
print(f'{username} is listening to music: {music}')
time.sleep(0.2)
def playing_football(username, game):
for i in range(10):
print(f'{username} is playing {game}')
time.sleep(0.1)
if __name__ == '__main__':
# 注意:创建子进程的代码必须写在 if main 中(否则在创建子进程时会被反复调用)
music_process = multiprocessing.Process(group=None, target=listening_music, name='music', args=('King', '真的爱你',))
football_process = multiprocessing.Process(group=None, target=playing_football, name='football',
kwargs={'username': 'King', 'game': '足球'})
t1 = time.time()
music_process.start() # 主进程等待子进程music_process执行完毕再往下执行
football_process.start() # 主进程等待子进程football_process执行完毕再往下执行
music_process.join()
football_process.join()
t2 = time.time()
print(f'总共耗时:{t2 - t1}')
进程编号
进程编号是进程唯一的标识,获取进程编号的目的是验证主进程和子进程的关系,可以得知道子进程是由哪个子进程创建而来
-
获取当前进程编号
import os pid = os.getpid()
或
import multiprocessing pid = multiprocessing.current_process().pid
-
获取当前进程父进程编号
import os ppid = os.getppid()
进程间数据独立
在创建子进程的时候,会将主进程的变量复制一份给子进程,其数据是不共享的
正常主进程结束子进程结束
默认情况下,主进程会等待所有子进程执行结束再结束
import multiprocessing
import time
def sing():
i = 1
for i in range(3):
print(f'{i}-是谁在唱歌...')
i += 1
time.sleep(0.1)
if __name__ == '__main__':
t1 = time.time()
print('主进程在执行')
sing_process = multiprocessing.Process(target=sing)
sing_process.start()
# time.sleep(5)
print('主进程执行完毕(注意:执行完毕不表示主进程结束)')
# Process finished with exit code 0 这句才表示主进程执行结束
主进程在执行
主进程执行完毕(注意:执行完毕不表示主进程结束)
0-是谁在唱歌…
1-是谁在唱歌…
2-是谁在唱歌…Process finished with exit code 0
设置子进程为守护进程
将子进程设置为守护进程,守护进程脱离终端控制,在后台运行(由linux内核管理);主进程会等待子进程结束之后再结束
sub_process = multiprocessing.Process(target=sing, daemon=True)
或
sub_process.daemon = True
import multiprocessing
import time
def sing():
i = 1
for i in range(3):
print(f'{i}-是谁在唱歌...')
i += 1
time.sleep(0.1)
print('子进程执行完毕')
if __name__ == '__main__':
t1 = time.time()
print('主进程在执行')
sing_process = multiprocessing.Process(target=sing, daemon=True)
sing_process.start()
time.sleep(5)
t2 = time.time()
print(f'主进程执行完毕,耗时{t2 - t1}')
主进程在执行
0-是谁在唱歌…
1-是谁在唱歌…
2-是谁在唱歌…
子进程执行完毕
主进程执行完毕,耗时5.027524948120117
中断子进程
if __name__ == '__main__':
sub_process = multiprocessing.Process(target=sing)
sub_process.terminate() # 强制结束子进程
# 僵尸进程:当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源
# 如果父进程先退出,子进程被init接管,子进程退出后,init会回收其占用的资源
进程的内存区域
-
代码区
-
全局变量区
-
堆区
-
栈区
3.2 线程
进程是分配资源的基本单位,一旦创建一个进程就会分配一定的资源
线程是CPU调度的基本单位,每个进程至少有一个线程,即所说的主线程
创建线程
- 导入线程模块
import threading
- 创建线程对象
线程对象 = threading.Thread(group=None, target=函数名, name=线程名称, args=(), kwargs={})
group: 参数未使用,始终为None
target: 表示调用对象,即子线程要执行的函数(回调函数入口地址)
name: 线程的名字
args: 线程要执行的函数的参数,以元组方式传参
kwargs: 线程要执行的函数的参数,以字典方式传参
- 启动线程
线程对象.start()
示例
import threading
import time
def coding(username, language_name):
for i in range(100):
print(f'{username} is programming in {language_name}-{i}')
time.sleep(0.2)
def listening(username, music_name):
for i in range(100):
print(f'{username} is listening to music {music_name}-{i}')
time.sleep(0.2)
if __name__ == '__main__':
t1 = time.time()
coding_thread = threading.Thread(name='coding', target=coding, args=('Ke Wang', 'Java'), daemon=True)
listening_thread = threading.Thread(name='listening', target=listening,
kwargs={'username': 'Ke Wang', 'music_name': '海阔天空'})
coding_thread.start()
listening_thread.start()
# 设置让主线程等待子线程完成任务后向下执行
# coding_thread.join() # 相当于把主线程阻塞
# listening_thread.join() # 相当于把主线程阻塞
t2 = time.time()
print('')
print(f'----------------- 主线程执行完成,用时{t2 - t1} -------------------')
线程特点
-
线程之间执行是无序的
-
主线程会等待所有子线程执行结束再结束
-
线程之间共享全局变量
守护线程
守护主线程就是主线程退出子线程销毁不再执行
线程ID
threading.current_thread()
线程共享变量
存在线程安全问题
import threading
import time
g_sum = 0
def sum1():
global g_sum
for i in range(1000000):
g_sum += 1
print(f'sum1中g_sum = {g_sum}')
def sum2():
global g_sum
for i in range(1000000):
g_sum += 1
print(f'sum2中g_sum = {g_sum}')
if __name__ == '__main__':
thread_1 = threading.Thread(target=sum1)
thread_2 = threading.Thread(target=sum2)
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
print('')
print(f'主线程中g_sum = {g_sum}')
互斥锁
保证在同一时刻只能用一个线程去操作全局变量。线程同步方式:互斥锁
- 创建互斥锁
e_lock = threading.Lock()
- 上锁
e_lock.acquire()
- 解锁
e_lock.release()
示例
import threading
g_sum = 0
e_lock = threading.Lock()
def sum1():
global g_sum
e_lock.acquire()
for i in range(1000000):
g_sum += 1
e_lock.release()
print(f'sum1中g_sum = {g_sum}')
def sum2():
global g_sum
e_lock.acquire()
for i in range(1000000):
g_sum += 1
e_lock.release()
print(f'sum2中g_sum = {g_sum}')
if __name__ == '__main__':
thread_1 = threading.Thread(target=sum1)
thread_2 = threading.Thread(target=sum2)
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
print('')
print(f'主线程中g_sum = {g_sum}')
sum1中g_sum = 1000000
sum2中g_sum = 2000000主线程中g_sum = 2000000
死锁
两个线程之间相关等待对方释放锁,可能会引起死锁问题
四、高级用法
4.1 with语句
上下文管理器with语句:更加简单、安全的处理资源和异常
特点:
with语句执行完成后,自动调用关闭文件操作,即使出现异常也会自动调用关闭文件的操作
以写的方式打开文件
with open('1.txt', 'w') as my_file:
my_file.write('文件内容')
4.2 上下文管理器
一个类只要实现了______enter______()和______exit______()这两个方法,通过该类创建的对象我们称为上下文管理器。
enter()表示上文方法,需要返回一个对象
exit()表示下文方法,with语句执行完成会自动执行,即使出现异常也会执行
with管理的对象就是上下文管理器:即with xxx as 上下文管理器
with xxx as 上下文管理器 中方法的调用顺序
1)init()
2)enter()
3)exit(self, exc_type, exc_val, exc_tb)
示例:
class MyFile(object):
def __init__(self, file_name, ops_model):
self.file_name = file_name
self.ops_model = ops_model
self.file_instance = None
def __enter__(self):
self.file_instance = open(self.file_name, self.ops_model, encoding='utf-8')
return self
def read_file(self):
total_content = ''
while True:
read_content = self.file_instance.read(1024)
if read_content == '':
break
total_content += read_content
return total_content
def __exit__(self, exc_type, exc_val, exc_tb):
self.file_instance.close()
if __name__ == '__main__':
with MyFile('./resource/py_test.txt', 'r') as my_file:
content = my_file.read_file()
print(f'文件内容:{content}')
4.3 生成器
什么是生成器
根据制定的规则循环生成数据,当条件不成立时则生成数据结束。数据不是一次性全部生成出来,而是使用一个,再生成一个,可以节约大量的内存
创建生成器的方式
-
生成器推导式
# 创建生成器 my_generator = (i * 2 for i in range(10))
注意:推导式用小括号()括起来
-
yield关键字
函数中使用yield关键字,那么这个函数就是生成器
def my_gen(num): for i in range(10): yield i # yield的作用:1)程序会执行到完这一句并返回;2)之后进入阻塞;3)再次调用next()时会继续执行
if __name__ == '__main__': my_generator2 = my_gen(3) my_gen = next(my_generator2) my_gen = next(my_generator2) my_gen = next(my_generator2)
遍历生成器
-
for循环
for i in my_generator: print(i)
-
next函数
next(my_generator)
while循环遍历
while True: try: i = next(my_generator) print(i) except StopIteration as e: break
五、正则表达式
正则表达式(Regular Expression),是使用单个字符串来描述,匹配某个句法规则的字符串,常被用来检索、替换符合某个模式的文本
Python中的正则表达式,使用re模块,并基于re模块中的三个基础方法来做正则匹配
5.1 基础匹配
在python中,使用re模块中的三个函数
-
re.match(匹配规则, 被匹配字符串)
从匹配字符串开头进行匹配,匹配成功后返回匹配对象,匹配不成功返回空
-
re.search(匹配规则,被匹配字符串)
搜索整个字符串,找出匹配的。从前向后,找到第一个后就停止,不会继续向后
-
findall(匹配规则,被匹配字符串)
匹配整个字符串,找出全部匹配项
5.2 元字符匹配
单字符匹配
字符 | 功能 |
---|---|
. | 匹配任意一个字符(除了\n),\. 匹配点本身 |
[] | 匹配[]中列举的字符 |
\d | 匹配数字,即0~9 |
\D | 匹配非数字 |
\s | 匹配空白,即空格,tab键 |
\S | 匹配非空白 |
\w | 匹配单词字符,即a~z, A~Z, 0~9, _ |
\W | 匹配非单词 |
示例:
-
[]
import re str = '今天是2024年12月11日,星期3,距离周日还有3天' result = re.findall(r'[距离]', str) print(result)
+ \d
```python
import re
str = '今天是2024年12月11日,星期3,距离周日还有3天'
# 在python中\表示转义字符,但这个要表示反斜杠\本身,所有在其前添加r,表示不转义
result = re.findall(r'\d', str)
print(type(result))
print(result)
[‘2’, ‘0’, ‘2’, ‘4’, ‘1’, ‘2’, ‘1’, ‘1’, ‘3’, ‘3’]
数量匹配
字符 | 功能 |
---|---|
* | 匹配前一个规则的字符出现0至无数次 |
+ | 匹配前一个规则的字符出现1至无数次 |
? | 匹配前一个规则的字符出现0次或1次 |
{m} | 匹配前一个规则的字符出现m次 |
{m,} | 匹配前一个字符的规则至少出现m次 |
{m,n} | 匹配前一个字符的规则出现m到n次 |
边界匹配
字符 | 功能 |
---|---|
^ | 匹配字符串开头 |
$ | 匹配字符串结尾 |
\b | 匹配一个单词的边界 |
\B | 匹配非单词的边界 |
分组匹配
字符 | 功能 |
---|---|
() | 把括号中字符做为一个分组 |
-
匹配邮箱地址
# 匹配邮箱地址,只运行匹配qq, 163, gmail这三种邮箱 email_reg = r'^[\w-]+(\.[\w-]+)*@(qq|163|gmail)\.[\w]+$' email = 'mux0809@163.com' result = re.match(email_reg, email) print(f'匹配邮箱规则:{result}')
匹配邮箱规则:<re.Match object; span=(0, 15), match=‘mux0809@163.com’>