# 面向对象
面向对象编程是一种编程范式或编程风格。它以类和对象为核心,将数据(属性)和操作(方法)封装在一起,通过继承和多态等机制实现代码的重用和扩展。
类是面向对象编程中的基本概念,它是一种抽象的数据类型,用于定义对象的属性和行为。类可以看作是对象的模板,通过类可以创建多个具有相同属性和行为的对象。
类的定义
在 Python 中,使用 class
关键字来定义一个类。
注意:类名通常使用大写字母开头,遵循驼峰命名法。
| |
| |
| |
| |
| class ClassName: |
| |
| name = "name" |
| |
| |
| def method(self): |
| print("method id:", self) |
| |
| |
| class_instance = ClassName() |
| print("class_instance id is:", class_instance) |
| class_instance.method() |
| |
| """ |
| 结果: |
| class_instance id is: <__main__.ClassName object at 0x000001CE2FEA9FD0> |
| method id: <__main__.ClassName object at 0x000001CE2FEA9FD0> |
| """ |
- 构造函数
__init__()
- 构造函数是类的一个特殊方法,用于初始化对象的状态。当创建对象时,Python 会自动调用构造函数。
- 构造函数的第一个参数必须是
self
,表示对象本身的引用。
- 构造函数可以接受任意数量的参数,用于初始化对象的属性。
- 构造函数可以返回任意类型的值,但通常返回
None
。
- 构造函数可以包含任意数量的代码,用于执行初始化操作。
- 构造函数可以调用其他方法,用于执行初始化操作。
| class ClassName: |
| def __init__(self, name): |
| self.name = name |
| |
| class_instance = ClassName("name") |
| print("class_instance.name is:", class_instance.name) |
- 析构函数
__del__()
- 析构函数是类的一个特殊方法,用于在对象被销毁时执行清理操作。当对象被销毁时,Python 会自动调用析构函数。
- 析构函数的第一个参数必须是
self
,表示对象本身的引用。
- 析构函数可以接受任意数量的参数,用于执行清理操作。
- 析构函数可以返回任意类型的值,但通常返回
None
。
- 析构函数可以包含任意数量的代码,用于执行清理操作。
- 析构函数可以调用其他方法,用于执行清理操作。
| class ClassName: |
| def __init__(self, name): |
| self.name = name |
| |
| def __del__(self): |
| print("del ClassName") |
| |
| class_instance = ClassName("name") |
| del class_instance |
# 封装
封装:面向对象编程中的一个重要概念,它指的是将对象的属性和方法封装在一起,形成一个独立的单元。
目的:隐藏对象的内部实现细节,只对外提供必要的接口,从而提高代码的可维护性和安全性。
在 Python 中,可以通过以下方式实现封装:
# 隐藏属性
使用 __
双下划线开头的属性名或方法名,表示私有,只能在类的内部访问。
| class ClassName: |
| name = "name" |
| __age = 18 |
| |
| class_instance = ClassName() |
| |
| print("class_instance.name is:", class_instance.name) |
| |
| print("class_instance.__age is:", class_instance.__age) |
| |
| |
| print("class_instance.__age is:", class_instance._ClassName__age) |
# 私有属性 / 方法
xxx
:普通属性 / 方法,可以在类的外部访问。
_xxx
:受保护的属性 / 方法,如果定义在类中,可以外部访问,也可以子类中访问。但是另外的 .py
文件通过 from import *
导入时, _xxx
属性 / 方法不会被导入。
- 这种一般是为了避免与 python 关键字冲突而采用的命名方法。
__xxx
:双下划线开头,隐藏的属性 / 方法,只能在类的内部访问,如果定义在类中,子类不会继承。
- 这种命名一般是 python 中的魔法方法或者属性,都是有特殊含义和功能的,自己不要轻易定义。
私有属性
| class ClassName: |
| name = "name" |
| _age = 18 |
| __sex = "male" |
| |
| class_instance = ClassName() |
| |
| print("class_instance.name is:", class_instance.name) |
| print("class_instance._age is:", class_instance._age) |
| print("class_instance.__sex is:", class_instance.__sex) |
| print("class_instance._ClassName__sex is:", class_instance._ClassName__sex) |
隐藏方法
| class Man: |
| def __play(self): |
| print("write code") |
| def funa(self): |
| |
| self.__play() |
| Man.__play(self) |
| |
| man = Man() |
| man.funa() |
| man.__play() |
| """ |
| 输出: |
| write code |
| """ |
私有方法
| class Gril: |
| def _play(self): |
| print("play game") |
| |
| gril = Gril() |
| gril._play() |
# 继承
继承:面向对象编程中的一个重要概念,它指的是一个类可以继承另一个类的属性和方法,从而实现代码的重用和扩展。
格式: class 子类名(父类名):
# 单继承
| class Persion: |
| def eat(self): |
| print("eat") |
| def sing(self): |
| print("sing") |
| |
| class Student(Persion): |
| pass |
| |
| student = Student() |
| student.eat() |
| student.sing() |
| """ |
| 输出: |
| eat |
| sing |
| """ |
# 继承的传递(多重继承)
子类可以继承父类的属性和方法,也可以继承父类的父类的属性和方法。
| class Persion: |
| def eat(self): |
| print("eat") |
| def sing(self): |
| print("sing") |
| |
| class Student(Persion): |
| pass |
| |
| class Teacher(Student): |
| pass |
| |
| teacher = Teacher() |
| teacher.eat() |
| teacher.sing() |
| """ |
| 输出: |
| eat |
| sing |
| """ |
# 重写
- 子类重写父类的方法
子类可以重写父类的方法,即在子类中定义一个与父类方法同名的方法,从而覆盖父类的方法。
| class Persion: |
| def eat(self): |
| print("eat") |
| |
| class Student(Persion): |
| def eat(self): |
| print("eat food") |
| |
| student = Student() |
| student.eat() |
| """ |
| 输出: |
| eat food |
| """ |
- 子类拓展父类的方法 (不会改变父类方法)
写法 1:子类在需要拓展的父类方法下写 父类名.方法名()
| class Persion: |
| def eat(self): |
| print("eat") |
| |
| class Student(Persion): |
| def eat(self): |
| Persion.eat(self) |
| print("eat food") |
| |
| |
| student1 = Student() |
| student1.eat() |
| |
| stuent2 = Persion() |
| stuent2.eat() |
| """ |
| 输出: |
| eat |
| eat food |
| eat |
| """ |
写法 2:子类在需要拓展的父类方法下写 super().方法名()
注意: super
在 python 里面是一个特殊的类,super () 是使用 super 类创建的一个对象,这个对象是父类,但是不是父类的实例,而是父类的子类,所以 super () 可以调用父类的方法。
| class Persion: |
| def eat(self): |
| print("eat") |
| |
| class Student(Persion): |
| def eat(self): |
| super().eat() |
| print("eat food") |
| |
| |
| student1 = Student() |
| student1.eat() |
| |
| stuent2 = Persion() |
| stuent2.eat() |
| """ |
| 输出: |
| eat |
| eat food |
| eat |
| """ |
# 新式类写法
python 中,类有两种写法:经典类和新式类。
class A
经典类:不由任意内置类型派生的类。
| class Animal: |
| def eat(self): |
| print("eat") |
| |
| class Dog(Animal): |
| pass |
| |
| |
| class Cat(Animal): |
| name = "cat" |
| def play(self): |
| print("play") |
class A()
class A(object)
新式类:继承了 object 类或者该类的子类都是新式类。 -- 推荐使用
object
类是所有类的基类,所有类都继承自 object 类,是 python 为所有对象提供的基类 (顶级父类)。
注意:python3 中如果一个类没有继承任何类,则默认继承 object
类,所以 python3 中所有的类都是新式类。
# 多继承
一个类可以继承多个类,多个类之间用逗号分隔。
| class Student: |
| def study(self): |
| print("study") |
| |
| class Teacher: |
| def teach(self): |
| print("teach") |
| |
| class TeacherStudent(Teacher, Student): |
| pass |
| |
| teacher_student = TeacherStudent() |
| |
| teacher_student.study() |
| teacher_student.teach() |
注意: 多个父类具有同名方法,则调用顺序为: 从左到右,深度优先
。
方法的搜索顺序:
python 中内置的 __mro__
属性可以查看类的继承顺序。
| class A: |
| def funa(self): |
| print("A.funa") |
| |
| class B(A): |
| def funb(self): |
| print("B.funb") |
| |
| class C(A): |
| def funa(self): |
| print("C.funa") |
| |
| class D(B, C): |
| pass |
| |
| d = D() |
| d.funa() |
| print(D.__mro__) |
| """ |
| 输出:(从左到右,深度优先) |
| (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) |
| """ |
# 多态
多态:面向对象编程中的一个重要概念,它指的是一个对象可以有多种形态,即同一个方法可以在不同的对象上调用,从而实现不同的功能。
多态的前提:
多态的体现:
| class Animal: |
| def eat(self): |
| print("eat") |
| |
| class Dog(Animal): |
| def eat(self): |
| print("dog eat") |
| |
| class Cat(Animal): |
| def eat(self): |
| print("cat eat") |
| |
| animal = Animal() |
| animal.eat() |
| |
| dog = Dog() |
多态性:
| class Animal: |
| def eat(self): |
| print("eat") |
| |
| class Dog(Animal): |
| def eat(self): |
| print("dog eat") |
| |
| class Cat(Animal): |
| def eat(self): |
| print("cat eat") |
| |
| def funa(obj): |
| obg.eat() |
| |
| animal = Animal() |
| funa(animal) |
| |
| dog = Dog() |
| funa(dog) |
| |
| cat = Cat() |
| funa(cat) |
# 静态方法
静态方法:不需要实例化对象就可以直接调用的方法,使用 @staticmethod
装饰器来定义。
静态方法的特点:
- 不需要实例化对象就可以直接调用
- 不需要
self
参数
- 静态方法可以访问类变量和实例变量
- 静态方法不能访问实例方法
静态方法的使用场景:当方法不需要访问实例变量和类变量时,可以使用静态方法。
| class Animal: |
| @staticmethod |
| def say_hello(): |
| print("hello") |
| |
| |
| |
| animal = Animal("dog") |
| animal.say_hello() |
| |
| |
| Animal.say_hello() |
注意:类方法可以直接方法时传参数,例如 Animal.say_hello (name)
# 类方法
类方法:使用 @classmethod
装饰器来定义,对于类方法,第一个参数必须是类对象,通常命名为 cls
,表示类本身。
| class Animal: |
| name = "animal" |
| @classmethod |
| def say_hello(cls): |
| print("hello") |
| |
| |
| |
| animal = Animal("dog") |
| animal.say_hello() |
| |
| |
| Animal.say_hello() |
当方法中需要使用到类对象(如访问私有类属性时),定义类方法
类方法一般配合类属性使用
总结:
- 实例方法:方法内部访问实例属性,方法内部可以通过
类名.类属性名
来访问类属性。
- 静态方法
@staticmethod
:方法内部,不需要访问实例属性和类属性。
- 如果需要访问类属性,方法内部可以通过
类名.类属性名
来访问,不能访问实例属性。
- 类方法
@classmethod
:方法内部只需要访问类属性,方法内部可以通过 cls.类属性名
来访问类属性,不能访问实例属性。
| class Person(object): |
| name = "小明" |
| def __init__(self): |
| self.age = 18 |
| |
| def play(self): |
| |
| print(f'{Person.name}在玩游戏') |
| |
| print(f'{self.age}岁') |
| |
| @staticmethod |
| def eat(): |
| print(f"{Person.name}eat food") |
| |
| |
| @classmethod |
| def say_hello(cls): |
| print(f'{cls.name}在说话') |
| |
# 单例模式
含义:一种常见的设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。
优点:节省内存,避免重复创建对象。
弊端:多线程访问容易引发线程安全问题。
方式
- 通过 @classmethod 实现
- 通过装饰器实现
- 通过重写__new__方法实现
- 通过模块导入实现
# __new__方法
__new__
方法是 object基类
提供的内置的 静态方法
,它是在对象被创建之前调用的,用于创建对象。 __new__
方法返回一个对象,这个对象会被 __init__
方法初始化。
作用:
| class Person(object): |
| def __init__(self, name): |
| print("Person.__init__") |
| self.name = name |
| |
| def __new__(cls, *args, **kwargs): |
| print("Person.__new__") |
| |
| res = super().__new__(cls) |
| return res |
| |
| person = Person("小明") |
| |
| """ |
| 输出: |
| Person.__new__ |
| """ |
# 通过重写__new__方法实现单例模式
设计流程:
- 定义一个类属性,初始化为 None,用来记录单利对象的引用
- 重写__new__方法
- 进行判断,如果类属性为 None,把__new__() 返回对象的引用保存进去
- 返回类型属性中记录的对象引用
| class Singleton(object): |
| __instance = None |
| def __new__(cls, *args, **kwargs): |
| print("Singleton.__new__") |
| return super().__new__(cls) |
| |
| def __init__(self): |
| print("Singleton.__init__") |
| |
| s1 = Singleton() |
| s2 = Singleton() |
| print(s1 is s2) |
# 通过导入模块实现单例模式
模块的 __init__.py
文件中的代码在模块第一次被导入时执行,只会执行一次,因此可以利用这个特性来实现单例模式。
| |
| class Singleton(object): |
| def __init__(self): |
| print("Singleton.__init__") |
| |
| def __new__(cls, *args, **kwargs): |
| print("Singleton.__new__") |
| return super().__new__(cls) |
| |
| singleton = Singleton() |
| |
| from my_singleton import singleton |
| |
| print(singleton) |
# 应用场景
-
- 回收站对象
-
- 音乐播放器
-
- 开发游戏软件 场景管理器
-
- 数据库配置、数据库连接池的设计
-
- 线程池、连接池、缓存、日志对象
# 魔法方法 & 魔法属性
魔法方法:在 Python 中,以双下划线开头和结尾的方法称为魔法方法,也称为特殊方法。魔法方法在特定的情况下自动调用,不需要手动调用。
# __doc__属性
__doc__
: 类、函数的描述信息
| class Person(object): |
| """这是一个描述信息""" |
| pass |
| print(Person.__doc__) |
| |
| def fun(): |
| """这是一个描述信息""" |
| pass |
| print(fun.__doc__) |
# __modeule__属性
__module__
: 类所属的模块名
| class Person(object): |
| pass |
| print(Person.__module__) |
# __class__属性
__class__
: 类所属的类名
| class Person(object): |
| pass |
| print(Person.__class__) |
# str () 方法
__str__
: 当使用 print 输出对象时,自动调用 __str__
方法,返回一个字符串
| class Person(object): |
| def __str__(self): |
| return "这是一个Person对象" |
| |
| person = Person() |
| print(person) |
# del () 方法
__del__
: 当对象被销毁时,自动调用 __del__
方法
| class Person(object): |
| def __del__(self): |
| print("Person对象被销毁") |
| |
| person = Person() |
| del person |
# call () 方法
__call__
: 当对象被当作函数调用时,自动调用 __call__
方法
callable: 判断对象是否可调用
| class Person(object): |
| def __call__(self, *args, **kwargs): |
| print("Person对象被当作函数调用") |
| |
| person = Person() |
| person() |
| |
| |
| print(callable(person)) |
# __dict__属性
__dict__
: 类或对象的属性字典
| class Person(object): |
| def __init__(self, name): |
| self.name = name |
| |
| person = Person("小明") |
| print(person.__dict__) |
# 文件操作
文件:存储在硬盘上的数据
文件操作步骤:
# 文件对象的方法
- open () 函数
open()
创建一个 file 对象,默认是以只读模式打开。
| file = open("文件路径", "打开模式") |
- read(n)
read()
方法用于读取文件内容,n 表示读取的字符个数,如果不指定 n,则表示读取整个文件。
| file = open("文件路径", "打开模式") |
| content = file.read() |
| file.close() |
- write()
write()
方法用于向文件中写入内容。
| file = open("文件路径", "打开模式") |
| file.write("要写入的内容") |
| file.close() |
- close()
close()
方法用于关闭文件。
| file = open("文件路径", "打开模式") |
| file.close() |
# 属性
- name
name
: 返回要打开文件的文件名,可以包含具体的路径。
| file = open("文件路径", "打开模式") |
| print(file.name) |
- mode
mode
: 返回打开文件时使用的模式,如’r’、‘w’、'a’等。
| file = open("文件路径", "打开模式") |
| print(file.mode) |
- closed
closed
: 返回文件是否已经关闭,True 表示已经关闭,False 表示已经打开。
| file = open("文件路径", "打开模式") |
| print(file.closed) |
# 读写操作
- 读操作
- read(size=-1)
read(size=-1)
: 从文件中读取 size 个字符,如果 size 未指定或为负数,则读取剩余的所有字符。
| file = open("文件路径", "打开模式") |
| content = file.read() |
| file.close() |
- readline(size=-1)
readline(size=-1)
: 从文件中读取一行,如果 size 未指定或为负数,则读取整行。
| file = open("文件路径", "打开模式") |
| content = file.readline() |
| file.close() |
- readlines(hint=-1)
readlines(hint=-1)
: 从文件中读取所有行,返回一个列表,如果 hint 未指定或为负数,则读取所有行。
| file = open("文件路径", "打开模式") |
| content = file.readlines() |
| file.close() |
# 访问模式
open()
函数的第二个参数,表示打开文件的模式,常用的模式有:
- ‘r’: 只读模式,如果文件不存在,会抛出异常。
- ‘w’: 写入模式,如果文件不存在,会创建文件;如果文件存在,会清空文件内容。
- ‘a’: 追加模式,如果文件不存在,会创建文件;如果文件存在,会在文件末尾追加内容。
- ‘b’: 二进制模式,可以与上述模式组合使用,如’rb’、‘wb’、'ab’等。
- ‘+’: 读写模式,可以与上述模式组合使用,如’r+'、‘w+’、'a+' 等。
- ‘r+’: 读写模式,如果文件不存在,会抛出异常;如果文件存在,可以同时进行读写操作。
- ‘w+’: 先写再读,文件存在就重新编辑文件,不存在就创建文件。
文件指针
文件指针:文件指针是指向文件中某个位置的指针,文件指针的初始位置为文件的开头,每次读写操作都会改变文件指针的位置。
- tell()
tell()
: 返回文件指针的当前位置。
| file = open("文件路径", "打开模式") |
| print(file.tell()) |
- seek(offset, whence=0)
seek(offset, whence=0)
: 移动文件指针到指定的位置, offset
表示偏移量, whence
表示参考位置,默认为 0 作为起始位置,表示文件开头。
| file = open("文件路径", "打开模式") |
| file.seek(10, 0) |
- truncate(size=None)
truncate(size=None)
: 截断文件,从文件指针的位置开始截断,截断后的文件大小为 size,如果 size 未指定,则截断到文件指针的位置。
| file = open("文件路径", "打开模式") |
| file.truncate(10) |
with open
语句可以自动关闭文件,不需要手动调用 close()
方法。
| with open("文件路径", "打开模式") as file: |
| content = file.read() |
# 编码格式
编码格式:文件的编码格式,常用的编码格式有 UTF-8、GBK 等。
| file = open("文件路径", "打开模式", encoding="编码格式") |
# 导入模块
os 模块:提供了许多与操作系统交互的函数,如文件操作、目录操作、环境变量操作等。
import os
# 文件重命名
指令: os.rename("旧文件名", "新文件名")
| os.rename("旧文件名.txt", "新文件名.txt") |
# 删除文件
指令: os.remove("文件名")
# 创建文件夹
指令: os.mkdir("文件夹名")
# 删除文件夹
指令: os.rmdir("文件夹名")
# 获取当前工作目录
指令: os.getcwd()
# 获取目录列表
指令: os.listdir("目录路径")
# 切换目录
指令: os.chdir("目录路径")
# 判断路径是否存在
指令: os.path.exists("路径")
# 判断是否为文件
指令: os.path.isfile("路径")
# 可迭代对象 Iterable
可迭代对象:可以被 for 循环遍历的对象,如列表、元组、字符串、字典、集合等。
- 可迭代对象的条件:
- 对象实现了__iter__() 方法
- iter () 方法返回迭代对象
- for 循环工作原理
- 先通过__iter__() 方法获取迭代器对象的迭代器
- 然后通过迭代器对象的__next__() 方法获取下一个元素并赋值给临时变量
- isinstance () 方法
- 判断一个对象是否是可迭代对象
isinstance(o,t)
o: 要判断的对象,t: 要判断的类型
Iterable:
可迭代对象
| from collections.abc import Iterable |
| |
| |
| print(isinstance([1, 2, 3], Iterable)) |
可迭代对象 Iterable 和迭代器 Iterator
凡是可以作用于 for
循环的对象都是 可迭代对象
Iterable 类型;
凡是可以作用于 next()
函数的对象都是 迭代器
Iterator 类型。
| from collections.abc import Iterable,Iterator |
| |
| |
| print(isinstance([1, 2, 3], Iterable)) |
| |
| |
| print(isinstance(iter([1, 2, 3]), Iterator)) |
| |
| |
| print(isinstance(iter([1, 2, 3]), Iterator)) |
总结:
- 可迭代对象不一定是迭代器,但迭代器一定是可迭代对象。
- iter () 函数可以将可迭代对象转换为迭代器。
- 如果一个对象拥有
__iter__()
方法,那么它就是可迭代对象
- 如果一个对象拥有
__next__()
方法,那么它就是迭代器
dir()
函数可以查看一个对象的所有属性和方法
# 迭代器协议
迭代器协议:迭代器协议是指迭代器对象必须实现 __next__()
方法, __next__()
方法返回下一个元素,如果没有元素了,会抛出 StopIteration
异常。
# 自定义迭代器类
两个特性: __iter__()
和 __next__()
方法
| class MyIterator: |
| def __init__(self, data): |
| self.data = data |
| self.index = 0 |
| |
| def __iter__(self): |
| return self |
| |
| def __next__(self): |
| if self.index < len(self.data): |
| result = self.data[self.index] |
| self.index += 1 |
| return result |
| else: |
| raise StopIteration |
| |
| |
| my_iter = MyIterator([1, 2, 3]) |
| for i in my_iter: |
| print(i) |
# 生成器 generator
python 中一边循环一边计算的机制,称为生成器(generator)。
- 生成器表达式
| for i in range(5) |
| print(i*5) |
| |
| |
| li = [i*5 for i in range(5)] |
| |
| gen = (i*5 for i in range(5)) |
| print(li) |
| print(gen) |
| |
| |
| print(next(gen)) |
| print(next(gen)) |
| print(next(gen)) |
| print(next(gen)) |
| print(next(gen)) |
# 生成器函数
python 中,只要函数体内部包含 yield
关键字,那么这个函数就变成一个生成器函数,调用生成器函数会返回一个生成器对象。
yield 关键字的作用是:
- 类似于 return, 将指定值或者多个值返回给调用者
- yield 语句一次返回一个结果,在每个结果中间,挂起函数,执行 next (), 再重新从挂起处开始执行
| def my_generator(): |
| yield 1 |
| yield 2 |
| yield 3 |
| gen = my_generator() |
| print(next(gen)) |
| print(next(gen)) |
| print(next(gen)) |
| """ |
| 输出: |
| 1 |
| 2 |
| 3 |
| """ |
| |
| |
| def my_generator(n): |
| li = [] |
| a = 0 |
| while a<n: |
| li.append(a) |
| a+=1 |
| yield a |
| print("生成器结束li:",li) |
| print(my_generator(5)) |
| for i in my_generator(5): |
| print(i) |
| """ |
| 输出: |
| 生成器结束li: [0, 1, 2, 3, 4] |
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| """ |
三者关系:
- 可迭代对象:指实现了 python 迭代协议,可以通过 for…in… 循环遍历的对象,比如列表 list、元组 tuple、字典 dict、集合 set、字符串 str、迭代器、生成器等。
- 迭代器:可以记住自己遍历位置的对象,直观体现就是可以 next () 函数返回值,迭代器只能往前,不能后退。(遍历完之后,再次调用 next () 会抛出 StopIteration 异常)
- 生成器:一种特殊的迭代器,迭代器不一定是生成器,它是 python 提供的通过简单方法写出的迭代器的一种手段
包含关系:可迭代对象(Iterable)-> 迭代器(Iterator)-> 生成器(Generator)
# 正则表达式
正则表达式:用于匹配字符串的规则,可以用来查找、替换、验证字符串等操作。
步骤:
- 导入 re 模块
- 使用 match () 函数进行匹配操作
- re.match (pattern, string, flags=0), pattern: 正则表达式,string: 要匹配的字符串,flags: 标志位,用于控制正则表达式的匹配方式
- 如果起始位置没有匹配成功,返回 None
- 如果上一步匹配成功,可以使用 Match 对象的 group () 方法获取匹配到的字符串
使用:
| import re |
| |
| result = re.match("a", "abc") |
| if result: |
| print(result.group()) |
| else: |
| print("匹配失败") |
# 匹配单个字符
符号 |
含义 |
. |
匹配除换行符以外的任意字符 |
\ |
转义字符,用于匹配特殊字符 |
[ ] |
匹配括号中的任意一个字符,例如 [a-z] 匹配任意一个小写字母 |
\w |
匹配字母、数字、下划线 |
\W |
匹配非字母、数字、下划线 |
\s |
匹配任意空白字符,包括空格、制表符、换页符等 |
\S |
匹配非空白字符 |
\d |
匹配数字 |
\D |
匹配非数字 |
\b |
匹配单词边界 |
\B |
匹配非单词边界 |
匹配任意字符
| import re |
| |
| re1 = re.match(".", "abc") |
| print(re1.group()) |
| re2 = re.match("1.", "123") |
| print(re2.group()) |
[]
匹配括号中的任意一个字符
| import re |
| |
| re1 = re.match("[abc]", "abc") |
| print(re1.group()) |
| re2 = re.match("[a-z]", "abc") |
| print(re2.group()) |
** \d
匹配数字
| import re |
| |
| re1 = re.match("\d", "123") |
| print(re1.group()) |
| re2 = re.match("\d", "abc") |
| print(re2.group()) |
# 匹配多个字符
符号 |
含义 |
* |
匹配前面的字符 0 次或多次 |
+ |
匹配前面的字符 1 次或多次 |
? |
匹配前面的字符 0 次或 1 次 |
|
匹配前面的字符 m 次 |
|
匹配前面的字符 m 到 n 次 |
*
匹配前面的字符 0 次或多次
| import re |
| |
| re1 = re.match("a*", "aaa") |
| print(re1.group()) |
| re2 = re.match("a*", "b") |
| print(re2.group()) |
| re3 = re.match("a*", "") |
| print(re3.group()) |
+
匹配前面的字符 1 次或多次
| import re |
| |
| re1 = re.match("a+", "aaa") |
| print(re1.group()) |
| re2 = re.match("a+", "b") |
| print(re2.group()) |
| re3 = re.match("a+", "") |
| print(re3.group()) |
?
匹配前面的字符 0 次或 1 次
| import re |
| |
| re1 = re.match("a?", "aaa") |
| print(re1.group()) |
# 匹配开头和结尾
符号 |
含义 |
^ |
匹配字符串的开头 |
$ |
匹配字符串的结尾 |
^
匹配字符串的开头
注意: ^
符号在 []
中是取反的意思
| import re |
| |
| re1 = re.match("^a", "abc") |
| print(re1.group()) |
$
匹配字符串的结尾
| import re |
| |
| re1 = re.match("c$", "abc") |
| print(re1.group()) |
# 匹配分组
符号 |
含义 |
| |
匹配左右任意一个表达式 |
(ab) |
将括号中的字符作为一个分组 |
\num |
引用分组 num 匹配到的字符串 |
(?P…) |
分组起别名 |
(?P=name) |
引用别名为 name 分组匹配到的字符串 |
|
匹配左右任意一个表达式
注意:优先从左到右匹配
| import re |
| |
| re1 = re.match("a|b", "abc") |
| print(re1.group()) |
| re2 = re.match("a|b", "b") |
| print(re2.group()) |
(ab)
将括号中的字符作为一个分组
| import re |
| |
| re1 = re.match('\w*@(qq|163|126).com', "123@163.com") |
| print(re1.group()) |
\num
引用分组 num 匹配到的字符串
应用:常在匹配标签时使用,例如匹配 <html>
标签
| import re |
| |
| re1 = re.match('<(\w*)>\w*</\\1>', '<html>login</html>') |
| print(re1.group()) |
| |
| re2 = re.match('<(\w*)><(\w*)>.*</\2></\1>', '<html><body>login</body></html>') |
| print(re2.group()) |
(?P<name>...)
分组起别名
(?P=name)
引用别名为 name 分组匹配到的字符串
使用:
| import re |
| |
| re2 = re.match('<(?P<l1>\w*)><(?P<l2>\w*)>.*</(?P=l2)></(?P=l1)>', '<html><body>login</body></html>') |
| print(re2.group()) |
示例:匹配网址
| import re |
| |
| |
| |
| li = ['www.baidu.com', 'www.google.com', 'www.sina.com', 'www.163.com', 'www.qq.com'] |
| for i in li: |
| res = re.match('www(\.)\w*\\1(com|cn|org)', i) |
| if res: |
| print(res.group()) |
# 高级用法
search()
函数:
在字符串中搜索匹配的子串,返回第一个匹配的子串,如果没有匹配的子串,则返回 None。
示例:
| import re |
| |
| res = re.search('\d', 'abc123') |
| print(res.group()) |
findall()
函数:
在字符串中搜索匹配的子串,返回所有匹配的子串,以列表形式返回。
示例:
| import re |
| |
| res = re.findall('\d', 'abc123') |
| print(res) |
sub()
函数:
在字符串中搜索匹配的子串,并替换为指定的字符串。
参数格式:
sub(pattern, repl, string, count=0)
pattern:
正则表达式,用于匹配子串
repl:
替换字符串
string:
要替换的字符串
count:
最大替换次数,0 表示无限制
示例:
| import re |
| |
| res = re.sub('\d', '0', 'abc123') |
| print(res) |
split()
函数:
在字符串中搜索匹配的子串,并按照匹配的子串将字符串分割成多个子串,以列表形式返回。
参数格式:
split(pattern, string, maxsplit=0, flags=0)
pattern:
正则表达式,用于匹配子串
string:
要替换的字符串
maxsplit:
最大分割次数,0 表示无限制
flags:
标志位,用于控制正则表达式的匹配方式,0 表示默认值
示例:
| import re |
| |
| res = re.split('\d', 'abc123') |
| print(res) |
compile()
函数:
将正则表达式编译成一个正则表达式对象,可以用于多次匹配操作。
参数格式:
compile(pattern, flags=0)
示例:
| import re |
| |
| pattern = re.compile('\d') |
| res = pattern.findall('abc123') |
| print(res) |
# 贪婪匹配和懒惰匹配
贪婪匹配:尽可能多的匹配字符
懒惰匹配:尽可能少的匹配字符
- 贪婪匹配 (默认)
| import re |
| |
| res = re.search('\d+', '123456') |
| print(res.group()) |
- 懒惰匹配
使用 ?
符号,表示懒惰匹配
示例:
| import re |
| |
| res = re.search('\d+?', '123456') |
| print(res.group()) |
# 原生字符串
在正则表达式中, \
符号用于转义特殊字符,例如 \d
表示匹配数字, \w
表示匹配字母或数字。
但是在 Python 中, \
符号也是转义字符,例如 \n
表示换行符, \t
表示制表符。因此,在正则表达式中使用 \
符号时,需要使用双反斜杠 \\
来转义。
例如, \d
需要写成 \\d
。
为了避免这种麻烦,可以使用原生字符串,即在字符串前加上 r
或 R
,例如 r'\d'
。
示例:
| import re |
| |
| res = re.search(r'\d+', '123456') |
| print(res.group()) |
注意:在正则表达式中,匹配字符串中的字符 \
时,需要 \\\\
, 加入原生字符串, \\
代表 \
# os 模块
# os 模块介绍
os 模块是 Python 标准库中的一个模块,提供了许多与 操作系统交互
的函数。使用 os
模块,可以执行文件和目录操作,如创建、删除、重命名文件和目录,获取文件和目录的属性等。
# os 模块常用函数
os.name
:获取操作系统的名称,例如 posix
表示 Linux
或 Mac
OS
X
, nt
表示 Windows。
os.getenv(key)
:获取环境变量的值 (环境变量名称)。
| import os |
| print(os.getenv('PATH')) |
os.path.split(path)
:将路径分割成目录和文件名,以元组的形式接收,第一参数为目录,第二参数为文件名。
| import os |
| print(os.path.split('/home/user/test.txt')) |
os.path.dirname(path)
:获取路径中的目录名。
| import os |
| print(os.path.dirname('/home/user/test.txt')) |
os.path.basename(path)
:获取路径中的文件名。
| import os |
| print(os.path.basename('/home/user/test.txt')) |
os.path.exists(path)
:判断路径 (文件或目录) 是否存在。
| import os |
| |
| print(os.path.exists('/home/user/test.txt')) |
| print(os.path.exists('/home/user/test1.txt')) |
os.path.isfile(path)
:判断路径是否为文件。
| import os |
| |
| print(os.path.isfile('/home/user/test.txt')) |
| print(os.path.isfile('/home/user')) |
os.path.isdir(path)
:判断路径是否为目录。
| import os |
| |
| print(os.path.isdir('/home/user')) |
| print(os.path.isdir('/home/user/test.txt')) |
os.path.abspath(path)
:获取绝对路径。
| import os |
| print(os.path.abspath('test.txt')) |
os.path.isabs(path)
:判断路径是否为绝对路径。
| import os |
| print(os.path.isabs('/home/user/test.txt')) |
| print(os.path.isabs('test.txt')) |
os.path.join(path, *paths)
:将多个路径组合成一个路径。
| import os |
| print(os.path.join('/home/user/', 'test.txt')) |
os.path.getsize(path)
:获取文件大小,单位为字节。
| import os |
| print(os.path.getsize('/home/user/test.txt')) |
# sys 模块
sys 模块是 Python 标准库中的一个模块,提供了许多与 Python解释器交互
的函数。使用 sys
模块,可以获取 Python 解释器的信息,如版本号、命令行参数等,还可以控制 Python 解释器的行为,如退出程序、改变标准输入输出等。
# sys 模块常用函数
sys.getdefaultencoding()
:获取 Python 解释器的默认编码。
| import sys |
| print(sys.getdefaultencoding()) |
sys.path()
:获取 Python 解释器的命令行参数。
| import sys |
| print(sys.path) |
sys.platform()
:获取 Python 解释器的平台信息。
| import sys |
| print(sys.platform) |
sys.version()
:获取 Python 解释器的版本信息。
| import sys |
| print(sys.version) |
# time 模块
time 模块是 Python 标准库中的一个模块,提供了许多与 时间
相关的函数。使用 time
模块,可以获取当前时间、格式化时间、时间戳等。
时间表示方式:
- 时间戳:从 1970 年 1 月 1 日 00:00:00 开始计算的秒数。
- 时间元组:包含年、月、日、时、分、秒、星期、年中的第几天等信息的元组。
- 字符串时间:按照指定格式表示时间的字符串。
# time 模块常用函数
time.time()
:获取当前时间的时间戳。
| import time |
| print(time.time()) |
time.localtime([secs])
:将时间戳转换为本地时间的时间元组。
返回元组元素:
索引 |
元素 |
说明 |
0 |
tm_year |
年 |
1 |
tm_mon |
月 |
2 |
tm_mday |
日 |
3 |
tm_hour |
时 |
4 |
tm_min |
分 |
5 |
tm_sec |
秒 |
6 |
tm_wday |
星期几 (0-6,0 表示周一) |
7 |
tm_yday |
一年中的第几天 (1-366) |
8 |
tm_isdst |
是否为夏令时 (0-1,0 表示不是) |
| import time |
| print(time.localtime()) |
| |
time.sleep(secs)
:暂停程序执行 secs 秒。
| import time |
| print('start') |
| time.sleep(5) |
| print('end') |
time.asctime(time_tuple)
:将时间元组转换为字符串时间。
| import time |
| print(time.asctime()) |
time.ctime()
:获取当前时间的时间戳。
| import time |
| print(time.ctime()) |
time.strftime(format, time_tuple)
:将时间元组转换为指定格式的字符串时间。
格式化符号:
符号 |
说明 |
%Y |
年 (4 位) |
%m |
月 (2 位) |
%d |
日 (2 位) |
%H |
时 (24 小时制,2 位) |
%M |
分 (2 位) |
%S |
秒 (2 位) |
%w |
星期几 (0-6,0 表示周一) |
%j |
一年中的第几天 (1-366) |
%a |
星期几的简写 (例如:Mon) |
%A |
星期几的全称 (例如:Monday) |
%b |
月份的简写 (例如:Jan) |
%B |
月份的全称 (例如:January) |
%z |
时区 (例如:+0800) |
%Z |
时区名称 (例如:CST) |
%x |
日期的字符串表示 (例如:10/15/21) |
%X |
时间的字符串表示 (例如:10:30:45) |
%c |
日期和时间的字符串表示 (例如:Fri Oct 15 10:30:45 2021) |
%U |
一年中的第几周 (以周日为一周的第一天) |
%W |
一年中的第几周 (以周一为一周的第一天) |
%V |
一年中的第几周 (以 ISO 8601 标准定义的一周为一周的第一天) |
%j |
一年中的第几天 (1-366) |
%U |
一年中的第几周 (以周日为一周的第一天) |
%W |
一年中的第几周 (以周一为一周的第一天) |
%V |
一年中的第几周 (以 ISO 8601 标准定义的一周为一周的第一天) |
| import time |
| print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) |
time.strptime(string, format)
:将字符串时间转换为时间元组。
| import time |
| print(time.strptime('2021-10-15 10:30:45', '%Y-%m-%d %H:%M:%S')) |
# logging 模块
logging 模块是 Python 标准库中的一个模块,提供了许多与 日志
相关的函数。使用 logging
模块,可以记录程序的运行信息,如错误、警告、调试信息等,方便程序调试和问题排查。
等级:
level |
等级 |
说明 |
NOTSET |
0 |
不设置级别,按照父 looger 的级别显示日志,如果 root logger, 那么会显示所有的 |
DEBUG |
10 |
调试信息,一般用于开发阶段 |
INFO |
20 |
一般信息,用于记录程序正常运行的信息 |
WARNING |
30 |
警告信息,用于记录可能的问题,但不影响程序的正常运行 |
ERROR |
40 |
错误信息,用于记录程序运行中出现的错误,但不影响程序的继续运行 |
CRITICAL(FATAL) |
50 |
严重错误信息,用于记录程序运行中出现的严重错误,可能导致程序崩溃 |
排序:NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL
| import logging |
| logging.debug('debug message') |
| logging.info('info message') |
| logging.warning('warning message') |
| logging.error('error message') |
| logging.critical('critical message') |
| """ |
| 输出: |
| DEBUG:root:debug message |
| INFO:root:info message |
| WARNING:root:warning message |
| ERROR:root:error message |
| CRITICAL:root:critical message |
| """ |
| |
# logging 模块常用函数
logging.basicConfig(**kwargs)
:配置 root logger 的参数,设置日志级别、日志格式、日志输出位置等。
参数:
参数 |
说明 |
level |
设置日志级别,默认为 WARNING 及以上 |
format |
设置日志格式,默认为’%(asctime) s - %(name) s - %(levelname) s - %(message) s’ |
datefmt |
设置日期格式,默认为’% Y-% m-% d % H:% M:% S’ |
filename |
设置日志输出文件名,默认为 None,表示输出到控制台 |
filemode |
设置日志输出文件模式,默认为’a’,表示追加;'w’表示覆盖 |
stream |
设置日志输出流,默认为 sys.stderr,表示输出到控制台 |
| import logging |
| logging.basicConfig(filename='log.log') |
| |
| logging.warning('warning message') |
| logging.error('error message') |
| logging.critical('critical message') |
# random 模块
random 模块是 Python 标准库中的一个模块,提供了许多与 随机数
相关的函数。使用 random
模块,可以生成随机数、随机选择、随机打乱等操作。
# random 模块常用函数
random.random()
:生成一个 0 到 1 之间的随机浮点数。
| import random |
| |
| print(random.random()) |
random.randint(a, b)
:生成一个 a 到 b 之间的随机整数。
| import random |
| |
| print(random.randint(1, 10)) |
random.choice(seq)
:从序列 seq 中随机选择一个元素。
| import random |
| |
| print(random.choice(['apple', 'banana', 'orange'])) |
random.sample(population, k)
:从 population 中随机选择 k 个不重复的元素,返回一个列表。
| import random |
| |
| print(random.sample([1, 2, 3, 4, 5], 3)) |
random.shuffle(x[, random])
:将序列 x 中的元素随机打乱。
| import random |
| |
| x = [1, 2, 3, 4, 5] |
| random.shuffle(x) |
| print(x) |
random.uniform(a, b)
:生成一个 a 到 b 之间的随机浮点数。
| import random |
| |
| print(random.uniform(1, 10)) |
random.randrange(start, stop[, step])
:生成一个从 start 到 stop 之间的随机整数,步长为 step。
| import random |
| |
| print(random.randrange(1, 10, 2)) |
format 方法是一种字符串格式化方法,用于将字符串中的占位符替换为指定的值。format 方法可以接受多个参数,也可以接受关键字参数。
| str.format(*args, **kwargs) |
参数:
*args
:位置参数,可以接受任意数量的位置参数,按照顺序替换占位符。
**kwargs
:关键字参数,可以接受任意数量的关键字参数,按照关键字替换占位符。
# 位置参数
| name = 'Alice' |
| age = 20 |
| print('My name is {0}, I am {1} years old.'.format(name, age)) |
# 关键字参数
| name = 'Alice' |
| age = 20 |
| print('My name is {name}, I am {age} years old.'.format(name=name, age=age)) |
# 占位符
占位符的语法为 {}
,可以包含以下内容:
:
:指定格式化方式,例如 {0:.2f}
表示将第一个参数格式化为保留两位小数的浮点数。
!
:指定转换方式,例如 {0!r}
表示将第一个参数转换为字符串表示。
#
:指定进制,例如 {0:#x}
表示将第一个参数格式化为十六进制表示。
*
:指定宽度,例如 {0:*<10}
表示将第一个参数格式化为宽度为 10 的字符串,左对齐。
+
:指定符号,例如 {0:+}
表示将第一个参数格式化为带符号的整数。
-
:指定对齐方式,例如 {0:-<10}
表示将第一个参数格式化为宽度为 10 的字符串,左对齐。
=
:指定填充字符,例如 {0:=^10}
表示将第一个参数格式化为宽度为 10 的字符串,居中对齐,填充字符为 =
。
0
:指定填充字符,例如 {0:0>10}
表示将第一个参数格式化为宽度为 10 的字符串,右对齐,填充字符为 0
。
,
:指定千位分隔符,例如 {0:,}
表示将第一个参数格式化为带千位分隔符的整数。
b
:将整数格式化为二进制表示。
| num = 1234567890 |
| print('The number is {0:,}'.format(num)) |
| print('The number is {0:b}'.format(num)) |
| print('The number is {0:#x}'.format(num)) |
| print('The number is {0:0>10}'.format(num)) |
| print('The number is {0:*<10}'.format(num)) |
| print('The number is {0:+}'.format(num)) |
| print('The number is {0:-<10}'.format(num)) |
| print('The number is {0:=^10}'.format(num)) |