Python面向对象

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基本的服务端

分为以下步骤

  1. 创建socket对象
# AF_INET: 表示internet之间通讯
# SOCK_STREAM:表示使用TCP协议发送字节流
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  1. 绑定IP和端口
server_socket.bind(('IP地址', 端口))
  1. 端口监听
server_socket.listen()
  1. 接收连接
server_socket.accept()
  1. 接收数据
server_socket.recv(缓冲区大小)
  1. 发送数据
server_socket.send(数据)
  1. 关闭连接
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中的多进程:先创建一个主进程,再由主进程创建子进程

创建进程

  1. 导入进程工具包
import multiprocessing
  1. 创建进程对象
子进程 = multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}

group: 参数未使用,始终为None

target: 表示调用对象,即子进程要执行的函数(回调函数入口地址)

name: 子进程的名字

args: 子进程要执行的函数的参数,以元组方式传参

kwargs: 子进程要执行的函数的参数,以字典方式传参

  1. 启动进程
进程对象.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调度的基本单位,每个进程至少有一个线程,即所说的主线程

创建线程

  1. 导入线程模块
import threading
  1. 创建线程对象
线程对象 = threading.Thread(group=None, target=函数名, name=线程名称, args=(), kwargs={})

group: 参数未使用,始终为None

target: 表示调用对象,即子线程要执行的函数(回调函数入口地址)

name: 线程的名字

args: 线程要执行的函数的参数,以元组方式传参

kwargs: 线程要执行的函数的参数,以字典方式传参

  1. 启动线程
线程对象.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}')

互斥锁

保证在同一时刻只能用一个线程去操作全局变量。线程同步方式:互斥锁

  1. 创建互斥锁
e_lock = threading.Lock()
  1. 上锁
e_lock.acquire()
  1. 解锁
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’>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值