从零开始学习python 11 (持续更新ing)
一、Python模块
Python 模块是组织代码的方式之一,可以将相关的功能、函数、类、变量等放在一个文件中,形成一个模块,其他程序可以通过 import
语句导入并使用这些功能。Python 模块使得代码更加模块化、可复用、可维护。
1. 什么是模块?
模块是一个 Python 文件,它定义了函数、类和变量,也可以包含可执行的代码。模块帮助你将代码分解为小块,使得代码更清晰、易维护和复用。
一个模块的文件名以 .py
结尾。例如,math.py
就是一个模块文件。
2. 如何创建模块
要创建一个模块,你只需要创建一个包含 Python 代码的 .py
文件。例如,创建一个名为 my_module.py
的模块:
# my_module.py
def greet(name):
print(f"Hello, {name}!")
def add(a, b):
return a + b
然后,你就可以在其他 Python 程序中导入并使用该模块。
3. 如何导入模块
使用 import
语句导入模块,有几种常见的方式:
-
导入整个模块:
import my_module
my_module.greet("Alice") # 调用 greet 函数
print(my_module.add(2, 3)) # 调用 add 函数
- 导入模块中的特定函数或类:
from my_module import greet
greet("Alice") # 只导入 greet 函数
- 给模块或函数取别名:
import my_module as mm
mm.greet("Bob") # 使用别名 mm 调用 greet
或者给函数取别名:
from my_module import add as sum_numbers
print(sum_numbers(2, 3)) # 使用别名 sum_numbers 调用 add 函数
4. Python 标准库模块
Python 提供了许多内置的标准库模块,这些模块可以直接导入使用,而不需要安装。例如:
math
:提供数学相关的功能。
import math
print(math.sqrt(16)) # 输出 4.0
os
:提供与操作系统交互的功能(如文件操作、路径操作)。
import os
print(os.getcwd()) # 输出当前工作目录
sys
:提供访问与 Python 解释器相关的变量和函数。
import sys
print(sys.version) # 输出 Python 版本
random
:提供生成随机数的功能。
import random
print(random.randint(1, 10)) # 输出 1 到 10 之间的随机整数
5. 模块搜索路径
当你导入一个模块时,Python 会在一系列目录中搜索该模块。这些目录包括:
- 当前目录
- Python 标准库目录
- Python 的
site-packages
目录
你可以通过 sys.path
查看 Python 模块的搜索路径:
import sys
print(sys.path)
如果要将自定义模块放在某个目录中,可以将该目录添加到 sys.path
中,或者将模块放在与主程序同一目录下。
6. __name__
和 __main__
每个模块都有一个内置的 __name__
属性。当一个模块被直接运行时,__name__
的值为 "__main__"
,如果模块是被导入的,__name__
的值为模块的名字。
这常用于编写模块时,既能作为独立程序执行,也能作为导入模块使用:
# my_module.py
def greet(name):
print(f"Hello, {name}!")
if __name__ == "__main__":
greet("World") # 只有在直接运行时才会执行
7. 模块的目录结构
如果你有多个相关模块,Python 提供了包(Package)来组织它们。包是一个包含多个模块的文件夹,文件夹中必须包含一个名为 __init__.py
的文件。
包的例子:
my_package/
__init__.py
module1.py
module2.py
然后,你可以通过以下方式导入:
from my_package import module1
from my_package.module2 import some_function
8. importlib
动态导入模块
你可以使用 Python 的 importlib
模块动态导入模块:
import importlib
# 动态导入 my_module
my_module = importlib.import_module("my_module")
my_module.greet("Alice")
9. 模块的重载
Python 会在第一次导入时加载模块并缓存。如果你修改了模块文件并希望重新加载模块,可以使用 importlib.reload()
来重载模块:
import importlib
import my_module
# 修改 my_module 后,重载它
importlib.reload(my_module)
10. 常见模块和库
除了 Python 标准库中提供的模块,Python 生态系统中还包含大量的第三方库,它们提供了很多额外的功能。以下是一些常见的第三方库:
- NumPy:用于高效的科学计算,支持大型多维数组和矩阵。
- Pandas:用于数据分析和操作,提供数据结构和数据分析工具。
- Requests:用于 HTTP 请求,简化与 Web 服务的交互。
- Flask:一个轻量级的 Web 框架。
- Django:一个功能全面的 Web 框架,适用于构建大型应用。
要安装这些库,可以使用 Python 的包管理工具 pip
:
pip install numpy
pip install requests
11. 总结
- 模块:是一个 Python 文件,可以包含函数、类、变量等。
- 导入模块:使用
import
语句,可以导入整个模块或模块中的特定内容。 - Python 标准库:Python 自带了丰富的标准库,如
math
、os
、sys
等。 - 包(Package):包含多个模块的文件夹,方便组织大型项目。
- 第三方库:Python 生态中有大量第三方库可以通过
pip
安装和使用。
二、迭代器与生成器
在 Python 中,迭代器(Iterator)和生成器(Generator)是两种重要的概念,它们帮助我们高效地遍历数据,特别是在处理大量数据时。虽然这两个概念有很多相似之处,但它们在实现和用途上存在一些显著的区别。
1. 迭代器(Iterator)
迭代器是一种可以在序列中按顺序访问元素的对象,它实现了两个核心方法:__iter__()
和 __next__()
。
1.1 迭代器的核心方法
__iter__()
:返回迭代器对象本身,通常用于初始化。__next__()
:返回序列的下一个元素。如果没有更多的元素,则抛出StopIteration
异常,表示迭代结束。
一个可迭代对象(如列表、元组、字符串)本身并不是迭代器,但它可以通过 iter()
函数转换为迭代器。可迭代对象是可以使用 for
循环的对象。
1.2 创建迭代器
我们可以手动实现一个自定义迭代器类。下面是一个简单的例子,创建一个迭代器遍历从 0 到指定 stop
值的数字。
class MyRange:
def __init__(self, start, stop, step=1):
self.start = start
self.stop = stop
self.step = step
def __iter__(self):
# 返回迭代器对象本身
return self
def __next__(self):
if self.start >= self.stop:
raise StopIteration # 当没有元素时抛出 StopIteration 异常
current = self.start
self.start += self.step
return current
# 使用自定义迭代器
my_range = MyRange(0, 5)
for number in my_range:
print(number)
输出:
0
1
2
3
4
1.3 迭代器的特点
- 懒加载:迭代器不会一次性将所有元素加载到内存中,而是按需逐个生成元素。适用于遍历大量数据。
- 状态管理:迭代器保存其当前状态,每次调用
__next__()
都会返回下一个元素,直到序列结束。 - 消耗性:一旦迭代器遍历完毕,它不能再次迭代。如果想重新遍历,需要重新创建一个新的迭代器对象。
2. 生成器(Generator)
生成器是 Python 提供的一种便捷的创建迭代器的方式。生成器通常是一个函数,它使用 yield
关键字来返回值,而不是像普通函数那样使用 return
返回一个值。
生成器的主要优势在于它们的 懒加载 特性:只有在需要的时候才生成下一个值,节省了大量内存。
2.1 使用 yield
创建生成器
生成器函数通过 yield
关键字返回一个值。每次调用生成器的 __next__()
方法时,执行到 yield
语句,返回一个值,并暂停函数的执行,保存函数的状态。下一次调用 __next__()
时,生成器从暂停的地方继续执行。
def my_range(start, stop, step=1):
while start < stop:
yield start # 返回当前值,并暂停执行
start += step
# 使用生成器
gen = my_range(0, 5)
for number in gen:
print(number)
输出:
0
1
2
3
4
2.2 生成器的特点
- 简洁:生成器通过
yield
语句创建,代码通常比使用类创建迭代器更简洁。 - 懒加载:与迭代器一样,生成器也不会一次性加载所有元素,而是按需生成。
- 状态保存:生成器在每次生成一个值时,会暂停执行并保存状态,直到下一次被调用时再继续。
- 消耗性:生成器是一次性的,迭代结束后,生成器对象不可重复使用。如果需要重新生成数据,必须重新调用生成器函数。
2.3 生成器表达式
生成器表达式是生成器的一种简写方式,它类似于列表推导式,但使用圆括号而不是方括号。生成器表达式不会一次性生成所有的值,而是每次生成一个值,具有懒加载特性。
gen = (x * x for x in range(5))
for num in gen:
print(num)
输出:
0
1
4
9
16
2.4 生成器与迭代器的比较
- 创建方式:
- 迭代器需要实现类并定义
__iter__()
和__next__()
方法。 - 生成器通过普通函数,使用
yield
关键字来创建。
- 迭代器需要实现类并定义
- 代码简洁性:
- 生成器通常更简洁,特别是当我们只需要返回一个单一的值时。
- 性能:
- 生成器和迭代器都使用懒加载,因此它们在内存使用上是高效的,尤其适合处理大规模数据。
- 状态管理:
- 迭代器需要手动管理状态,而生成器自动管理其状态。
3. 迭代器和生成器的应用
-
处理大数据:迭代器和生成器非常适合处理大量数据,比如读取大文件、生成大范围的数列等,因为它们采用懒加载,避免一次性将所有数据加载到内存中。
-
内存效率:当你需要遍历大量数据但不需要存储所有数据时,生成器和迭代器非常有效,它们仅在需要时生成数据。
-
流式处理:生成器和迭代器适合实现流式处理,比如从网络中按需获取数据,逐步处理数据流。
4. 总结
- 迭代器(Iterator):是一种能够记住当前状态并按需提供下一个元素的对象,必须实现
__iter__()
和__next__()
方法。适合需要手动控制的迭代操作。 - 生成器(Generator):通过
yield
关键字创建的迭代器,是一种更加简洁、优雅的创建迭代器的方式。它与迭代器具有相同的懒加载特性,但通常更简洁,适合快速实现按需生成的迭代器。
三、正则表达式
正则表达式(Regular Expressions,简称 Regex 或 RegEx)是一个强大的工具,用于匹配字符串中的特定模式。它在字符串的搜索、替换、分割、提取等任务中非常有用。正则表达式广泛应用于文本处理、数据验证、日志分析等场景。
1. 正则表达式的基本概念
正则表达式是一种由特殊字符组成的字符串,描述了一个文本模式。通过正则表达式,可以检索、匹配或替换符合某个模式的字符串。
2. 正则表达式的基本语法
2.1 普通字符
- 字母、数字、下划线:正则表达式中的普通字符会直接匹配它们自己。例如,
a
匹配字符 "a",1
匹配数字 "1"。
2.2 特殊字符
有一些特殊字符在正则表达式中有特殊的含义,例如匹配任意字符、开始和结束位置等。
-
.
:匹配任意字符(除了换行符)。
import re
re.match('a.c', 'abc') # 匹配成功,返回一个 match 对象
^
:匹配字符串的开头。
re.match('^a', 'abc') # 匹配成功,表示字符串以 'a' 开头
-
$
:匹配字符串的结尾。
re.match('c$', 'abc') # 匹配成功,表示字符串以 'c' 结尾
[]
:表示字符类,匹配方括号中的任意一个字符。
re.match('[aeiou]', 'apple') # 匹配成功,'a' 是元音字母之一
|
:表示“或”操作,匹配符号左边或右边的任意一个模式。
re.match('apple|banana', 'apple') # 匹配成功
2.3 量词
量词指定模式中元素的重复次数。
-
*
:匹配前面的表达式 0 次或多次。
re.match('a*b', 'aaaaab') # 匹配成功,表示 'a' 可以出现任意次
+
:匹配前面的表达式 1 次或多次。
re.match('a+b', 'aaaaab') # 匹配成功,表示 'a' 至少出现一次
?
:匹配前面的表达式 0 次或 1 次。
re.match('a?b', 'ab') # 匹配成功
{n}
:匹配前面的表达式恰好 n 次。
re.match('a{3}', 'aaa') # 匹配成功
{n,}
:匹配前面的表达式至少 n 次。
re.match('a{2,}', 'aaaa') # 匹配成功,至少有两个 'a'
{n,m}
:匹配前面的表达式至少 n 次,最多 m 次。
re.match('a{2,4}', 'aaa') # 匹配成功,'a' 的数量是 2 到 4 次
2.4 元字符
-
\d
:匹配任何数字字符,等价于[0-9]
。
re.match('\d', '5') # 匹配成功,表示 '5' 是数字
\D
:匹配任何非数字字符,等价于[^0-9]
。
re.match('\D', 'a') # 匹配成功,表示 'a' 不是数字
\w
:匹配任何字母、数字或下划线字符,等价于[a-zA-Z0-9_]
。
re.match('\w', 'A') # 匹配成功
\W
:匹配任何非字母、非数字、非下划线字符,等价于[^a-zA-Z0-9_]
。
re.match('\W', '@') # 匹配成功
\s
:匹配任何空白字符,包括空格、制表符、换行符等。
re.match('\s', ' ') # 匹配成功,表示空格是空白字符
\S
:匹配任何非空白字符。
re.match('\S', 'a') # 匹配成功,表示 'a' 不是空白字符
2.5 分组与捕获
-
()
:括号用于分组,将多个字符组合成一个单元,并且可以对其进行引用。匹配的内容会被捕获,后续可以通过编号进行引用。
match = re.match(r'(\d+)', '12345')
print(match.group(1)) # 输出 '12345'
(?P<name>...)
:为分组命名,方便通过组名来引用。
match = re.match(r'(?P<number>\d+)', '12345')
print(match.group('number')) # 输出 '12345'
2.6 非捕获分组
-
(?:...)
:用于分组但不捕获匹配的内容,常用于需要分组,但不希望返回该分组的场景。
re.match(r'(?:abc)+', 'abcabc') # 匹配 abcabc,但不捕获 'abc'
2.7 前瞻和后顾
-
(?=...)
:正向前瞻,要求后面的字符符合某个模式,但不消耗字符。
re.match(r'\d+(?=\s)', '123 ') # 匹配数字 '123' 后面跟一个空格,但不包括空格
(?!...)
:负向前瞻,要求后面的字符不符合某个模式。
re.match(r'\d+(?!\s)', '1234a') # 匹配数字 '1234' 后面不跟空格
(?<=...)
:正向后顾,要求前面的字符符合某个模式,但不消耗字符。
re.match(r'(?<=\s)\d+', ' abc') # 匹配空格后面的数字
(?<!...)
:负向后顾,要求前面的字符不符合某个模式。
re.match(r'(?<!\d)\D+', 'abc') # 匹配非数字字符,前面不跟数字
3. 正则表达式的常见操作
在 Python 中,使用 re
模块来处理正则表达式,常见操作包括:
-
re.match(pattern, string)
:从字符串的开始位置匹配正则表达式,如果匹配成功返回一个 match 对象,否则返回None
。
re.match(r'\d+', '123abc') # 匹配数字,返回 match 对象
re.search(pattern, string)
:在整个字符串中搜索正则表达式,找到第一个匹配的部分并返回 match 对象。如果没有找到,返回None
。
re.search(r'\d+', 'abc123xyz') # 匹配数字,返回 match 对象
re.findall(pattern, string)
:返回字符串中所有匹配正则表达式的部分,以列表的形式返回。
re.findall(r'\d+', 'abc123xyz456') # 返回 ['123', '456']
re.sub(pattern, repl, string)
:替换字符串中匹配正则表达式的部分。
re.sub(r'\d+', 'NUMBER', 'abc123xyz456') # 返回 'abcNUMBERxyzNUMBER'
re.split(pattern, string)
:使用正则表达式分割字符串。
re.split(r'\s+', 'hello world ') # 返回 ['hello', 'world']
4. 总结
正则表达式是一种强大的文本处理工具,能够帮助你高效地进行字符串搜索、匹配、提取、替换和验证。掌握正则表达式的基本语法和操作,可以大大提高处理文本的效率和灵活性。