Bootstrap

学习日志011--模块,迭代器与生成器,正则表达式

一、python模块

在之前学习c语言时,我们学了分文件编辑,那么在python中是否存在类似的编写方式?答案是肯定的。python中同样可以实现分文件编辑。甚至还有更多的好处:

  1. 提高代码的可维护性‌:当代码被分成多个文件时,每个文件可以专注于实现特定的功能或模块。这使得查找和修复错误变得更加容易。可以更方便地对代码进行局部修改,而不需要浏览整个项目的代码。

  2. 增强代码的可读性‌:分文件编程允许开发者使用描述性的文件名,这些文件名能够清晰地传达文件内容或功能。每个文件的内容更加专注和精简,减少了代码的复杂性,使得其他开发者更容易理解代码的逻辑。

  3. 促进代码重用‌:将通用功能或模块独立成单独的文件,可以在多个项目或程序之间重用这些代码,而无需复制粘贴。通过导入所需的模块,可以轻松地复用代码,减少重复劳动和潜在的错误。

  4. 便于团队协作‌:在大型项目中,多个开发者可以同时编辑不同的文件,而不需要担心相互之间的冲突。使用版本控制系统(如Git)时,分文件编程使得跟踪变化、合并代码和解决冲突更加容易。

  5. 提高程序的加载速度‌:在需要时动态地导入模块,可以减少程序启动时的加载时间,因为只有在需要时才加载相关的代码。这对于大型应用程序尤其重要,可以显著提高程序的响应速度。

  6. 组织代码结构‌:通过将代码分成不同的文件,可以更容易地组织代码的结构,使其符合逻辑和功能上的划分。这有助于实现更清晰的层次结构和模块化设计。

  7. 便于单元测试‌:分文件编程使得为每个模块或功能编写单元测试变得更加容易。这有助于确保代码的正确性,并在修改代码时快速发现问题。

  8. 减少命名冲突‌:将代码分成不同的文件(模块)可以减少变量、函数和类名之间的命名冲突。每个文件可以有自己的命名空间,使得代码更加清晰和易于管理。

分文件编辑在Python编程中是一种非常有益的做法。它不仅提高了代码的质量,还使得开发和维护过程更加高效和顺畅。而这些一个个文件则在python称为模块

import

分文件编辑(模块)的关键字--import

不同文件在同一目录下时,可以直接使用import来引用该模块的内容,包括不限于函数,变量等

在Python中,如果你想要在同一个目录(文件夹)下导入一个模块,你需要确保几个关键点:

  1. 模块文件‌:确保你想要导入的文件是一个有效的Python模块,即以.py为扩展名,并且包含了你想要导入的函数、类或变量。

  2. init.py‌:如果你的模块位于一个包(包含多个模块的目录)中,确保包的目录中有一个__init__.py文件。这个文件可以是空的,但它的存在会告诉Python这个目录应该被视为一个包。对于Python 3.3及以后的版本,即使没有__init__.py文件,包导入也可以工作,但最好还是包含这个文件以保持兼容性。

  3. 导入语句‌:使用正确的导入语句。如果你想要导入同目录下的module_name.py文件中的内容,你可以简单地使用:

    import module_name
    

    或者,如果你想要导入该模块中的特定函数、类或变量,你可以使用:

    from module_name import specific_function_or_class
    

 包

什么是包

当我们使用模块的内容写代码时非常爽,可是当我们回头读代码时,看着一行行的import难免战战兢兢汗如雨下。为了让模块的引用更简洁,更直观。我们将类似的模块放入同一个文件夹内,并创建一个__init__.py作为标识符。这样的一个文件夹被称为包。这锅__init__是不是很熟悉,我们在创建类的时候也遇见过他哦

要在你的Python程序中使用包中的模块,你需要使用import语句来导入它们。你可以导入整个模块,也可以从模块中导入特定的函数、类或变量。

例如,要导入module1并使用function1,你可以这样做:

import mypackage.module1

mypackage.module1.function1()
# 输出: This is function1 from module1.

 或者,你可以直接从module1中导入function1

from mypackage.module1 import function1

function1()
# 输出: This is function1 from module1.

要导入子包中的模块,你可以使用类似的语法:

import mypackage.subpackage.module3

mypackage.subpackage.module3.function3()
# 输出: This is function3 from subpackage.module3.

或者

from mypackage.subpackage import module3

module3.function3()
# 输出: This is function3 from subpackage.module3.

在大多数情况下,只要你的包和模块位于你的脚本或当前工作目录的某个子目录中,Python就应该能够找到它们。在导入包或模块时,Python会按照sys.path列表中的目录顺序来查找它们。如果Python找不到你想要导入的包或模块,你可能需要将包含它们的目录添加到sys.path中。 

import sys

print(sys.path)

 输入这串代码后,你会得到一些文件目录

D:\\xn\\hqyj\\pythonProject\\.venv\\Lib\\site-packages'

其中这样的路径,打开后,就是存放包的地方。我们平时下载的包都存在这,你要是想的话也可以将自己定义的包放在这,这样以后不论在电脑哪里编写文件,都可以访问他们.

内置

除了自己编写或从网上下载外,python中还附带丰富的内置模块供给我们使用。

模块名称

模块描述

os

os 模块提供了许多与操作系统交互的函数,例如创建、移动和删除文件和目录,以及访问环境变量等。

sys

sys 模块提供了与 Python 解释器和系统相关的功能,例如解释器的版本和路径,以及与 stdin、stdout 和 stderr 相关的信息。

time

time 模块提供了处理时间的函数,例如获取当前时间、格式化日期和时间、计时等。

datetime

datetime 模块提供了更高级的日期和时间处理函数,例如处理时区、计算时间差、计算日期差等。

math

math 模块提供了数学函数,例如三角函数、对数函数、指数函数、常数等。

json

json 模块提供了 JSON 编码和解码函数,可以将 Python 对象转换为 JSON 格式,并从 JSON 格式中解析出 Python 对象。

numpy

一个用于维度数组计算的库

opencv

一个用于计算机视觉的库

matplotlib

一个用于数据可视化的库(绘图)

scikit-learn

一个用于机器学习的库

tensorflow

一个用于深度学习的库

threading

一个用于设置多线程的库

二、迭代器与生成器。

迭代器

还记得我们学习高阶函数时的map()函数吗?那是留下了一个问题,map返回了一个迭代器对象。什么是迭代器,今天我们就将解答这个问题。

迭代器是一种集合,和我们之前学的列表,集合,元组类似。不同的是我们无法直接去看到他,只有在运行时才会出现。应为他的这种特性,在编写程序时可以节省大量的内存空间,而列表等数据类型,在定义时就确认大小了。此外一个迭代器类型包含__iter__,和__next__两种方法。从他们的宛若单链表名字上我们还可以看出迭代器的特性--不可回退性。那让我们来定义一个迭代器吧

class My_iter:
    def __init__(self,start,stop,step):
        self.start = start
        self.stop = stop
        self.step = step

    def __iter__(self):
        return self

    def __next__(self):
        if self.start < self.stop:
            x = self.start
            self.start += self.step
            return x
        else:
            raise StopIteration("迭代已完成")
my_iter = My_iter(1,10,2)
try:
    while True:
        print(next(my_iter))
except Exception as e:
    print(e)

这里我仿照range编写了一个简单的迭代器__init__来接受实例的数值,__iter__用来返回自生,__next__来推进迭代器.RAISE用来抛出异常,这样子死循环时,当迭代器结束时,循环也跟着结束。根据需要可以进行更改,但一定不要少了__iter__,__next__

生成器

在python中,使用了 yield 的函数就被称为——生成器。
yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。
与普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单的理解【生成器就是一个迭代器】。
每次使用yield语句生产一个值之后,函数都将暂停执行【内存释放出来】,等待再次唤醒。
yield语句和return语句的差别就在于yield语句返回的是可迭代对象,而return返回的是不可迭代对象。
每次调用生成器的next()方法或者使用for或while循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇见yield语句。 

def create1(n):
    while n>0:
        yield n
        n -= 1
create_iter = create1(10)
for i in create_iter:
    print(i)

三、正则表达式

正则表达式(Regular Expression,简称 regex 或 regexp)是一种强大的文本处理工具,用于搜索、匹配和替换文本中的字符组合。它最初是由数学家Stephen Kleene在20世纪50年代提出的,作为描述字符串集合的一种方式,后来被广泛应用于编程语言和文本编辑器中。

正则表达式由一系列特殊字符和普通字符组成,这些特殊字符称为元字符(metacharacters),它们具有特殊的含义,用于匹配不同类型的字符或字符组合。例如,. 匹配任意单个字符,* 匹配前一个字符零次或多次,+ 匹配前一个字符一次或多次,[abc] 匹配方括号内的任意一个字符,`` 匹配字符串的开始,$ 匹配字符串的结束等。

通过组合这些元字符和普通字符,可以创建出复杂的模式来匹配特定的文本。例如,正则表达式 \d{3}-\d{2}-\d{4} 可以匹配美国社会保险号码的格式(如 123-45-6789),其中 \d 表示匹配任意数字,{3}、{2} 和 {4} 分别表示匹配前一个字符3次、2次和4次。

正则表达式在编程中非常有用,特别是在文本处理、数据验证、网络爬虫、日志分析等领域。许多编程语言都支持正则表达式,如Python、JavaScript、Java、Perl等,它们通常提供了内置的库或函数来处理正则表达式。

学习和使用正则表达式需要一定的时间和实践,因为正则表达式的语法和规则相对复杂。但是,一旦掌握了它的基本原理和常用模式,就可以大大提高文本处理的效率和准确性。

python中正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。re模块使 Python 语言拥有全部的正则表达式功能。

re.match()

re.match() 是 Python 中正则表达式模块 re 的一个函数,用于从字符串的开始位置匹配正则表达式。如果匹配成功,它返回一个匹配对象;否则,它返回 None

import re

# 基本格式
match_object = re.match(pattern, string, flags=0)

pattern是正则表达式,string是字符串,flags是可选参数,用来实现复杂的功能

import re

pattern = r'\d+'  # 匹配一个或多个数字
string = '123abc'

match_object = re.match(pattern, string)

if match_object:
    print('匹配成功:', match_object.group())  # 输出: 匹配成功: 123
else:
    print('匹配失败')

在这个例子中,正则表达式 \d+ 匹配一个或多个数字。由于字符串 '123abc' 以数字开头,所以匹配成功,并返回匹配对象。使用 group() 方法可以获取匹配的文本。 

 失败的情况

import re

pattern = r'\d+'
string = 'abc123'

match_object = re.match(pattern, string)

if match_object:
    print('匹配成功:', match_object.group())
else:
    print('匹配失败')  # 输出: 匹配失败

使用的标志

import re

pattern = r'[A-Z]+'  # 匹配一个或多个大写字母
string = 'Hello123'

# 使用 re.IGNORECASE 标志,使匹配不区分大小写
match_object = re.match(pattern, string, re.IGNORECASE)

if match_object:
    print('匹配成功:', match_object.group())  # 输出: 匹配成功: H
else:
    print('匹配失败')

re.search()

 re.search() 是 Python 中正则表达式模块 re 的另一个核心函数。与 re.match() 不同的是,re.search() 会在整个字符串中搜索与正则表达式匹配的第一个位置,而不是仅仅从字符串的开始位置进行匹配。如果找到匹配项,它会返回一个匹配对象;否则,返回 None

import re

# 基本格式
match_object = re.search(pattern, string, flags=0)

示例

import re

pattern = r'\d+'  # 匹配一个或多个数字
string = 'abc123def'

match_object = re.search(pattern, string)

if match_object:
    print('匹配成功:', match_object.group())  # 输出: 匹配成功: 123
else:
    print('匹配失败')

在这个例子中,正则表达式 \d+ 匹配一个或多个数字。字符串 'abc123def' 中包含数字 '123',所以 re.search() 找到匹配项并返回匹配对象。

使用标志

import re

pattern = r'[a-z]+'  # 匹配一个或多个小写字母
string = '123ABCdef'

# 使用 re.IGNORECASE 标志,使匹配不区分大小写
match_object = re.search(pattern, string, re.IGNORECASE)

if match_object:
    print('匹配成功:', match_object.group())  # 输出: 匹配成功: ABC
else:
    print('匹配失败')

在这个例子中,虽然字符串 '123ABCdef' 中首先出现的是数字和大写字母,但由于使用了 re.IGNORECASE 标志,正则表达式 [a-z]+ 也能匹配到大写字母(实际上匹配到了 'ABC',因为它是第一个出现的小写或大写字母序列)。注意,这里的匹配是从左到右进行的,所以它会匹配到第一个符合条件的序列。

 re.findall()

re.findall() 是 Python 中正则表达式模块 re 提供的一个函数,用于在整个字符串中查找所有与正则表达式匹配的子串,并将它们作为一个列表返回。如果没有找到任何匹配项,它将返回一个空列表。 

import re

# 基本格式
matches = re.findall(pattern, string, flags=0)

查找所有匹配项

import re

pattern = r'\d+'  # 匹配一个或多个数字
string = 'abc123def456ghi789'

matches = re.findall(pattern, string)
print(matches)  # 输出: ['123', '456', '789']

 在这个例子中,正则表达式 \d+ 匹配一个或多个数字。字符串 'abc123def456ghi789' 中包含三个数字序列 '123''456' 和 '789',所以 re.findall() 返回一个包含这些匹配项的列表。

使用标志

import re

pattern = r'[a-z]+'  # 匹配一个或多个小写字母
string = 'Hello123World456'

# 使用 re.IGNORECASE 标志,使匹配不区分大小写
matches = re.findall(pattern, string, re.IGNORECASE)
print(matches)  # 输出: ['Hello', 'World']

 三者区别

  1. re.match 从首字母匹配,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None。
  2. re.search 匹配整个字符串,直到找到一个对应匹配【若有多个,也只返回第一个】。
  3. re.findall 返回匹配到的所有子串。

可选修饰符

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。如 re.I | re.M 被设置成 I 和 M 标志:

修饰符

描述

re.I

使匹配对大小写不敏感。

re.L

做本地化识别(locale-aware)匹配。

re.M

多行匹配,影响 ^ 和 $。

re.S

使 . 匹配包括换行在内的所有字符。

re.U

根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B。

re.X

该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

import re
s = 'Good good study, Day day up'
ret = re.findall('good', s, re.I)
print(ret)

 正则表达式模式

模式字符串使用特殊的语法来表示一个正则表达式。

  1. 字母和数字表示他们自身。
  2. 一个正则表达式模式中的字母和数字匹配同样的字符串。
  3. 多数字母和数字前加一个反斜杠时会拥有不同的含义。
  4. 标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
  5. 反斜杠本身需要使用反斜杠转义。

由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。

正则表达式(Regular Expression,简称 regex 或 regexp)是一种用来匹配字符串中字符组合的模式。它主要用于搜索、替换和解析字符串。正则表达式由一些普通字符和特殊字符(称为元字符)组成,这些特殊字符赋予了正则表达式强大的匹配能力。

以下是一些常见的正则表达式模式和元字符的简介:

  1. 普通字符‌:

    • 普通字符(如字母、数字、标点符号等)在正则表达式中匹配它们自身。
    • 例如,正则表达式 abc 会匹配字符串中的 abc
  2. 元字符‌:

    • .:匹配除换行符 \n 之外的任何单个字符。
    • ``:匹配字符串的开始位置。
    • $:匹配字符串的结束位置。
    • *:匹配前面的字符零次或多次。
    • +:匹配前面的字符一次或多次。
    • ?:匹配前面的字符零次或一次。
    • {n}:匹配前面的字符恰好 n 次。
    • {n,}:匹配前面的字符至少 n 次。
    • {n,m}:匹配前面的字符至少 n 次,但不超过 m 次。
    • []:匹配方括号中的任意一个字符。例如,[abc] 匹配 ab 或 c
    • |:表示或运算,例如 a|b 匹配 a 或 b
    • ():用于分组和捕获。例如,(abc) 会捕获匹配到的 abc
import re

s1 ='AuhewoBhsoh023'

try:
    def fun1(s:str):
        ret = re.match(r"[A-Z][a-z]*",s)
        if ret:
            print(ret.group())
        else:
            print("匹配不成功")


    fun1(s1)
except Exception as e:
    print(e)

from re import match


def fun_1(s):
    ret = match(r"[a-zA-Z]+[\w]",s)
    if ret:
        print(ret.group())
    else:
        print("没有匹配到")

s="_23onf"
fun_1(s)
import re
def fun3(pwd):
    ret = re.match(r'^\w{8,20}5$',pwd)
    if ret:
        print(ret.group())
    else:
        print("密码不正确")

fun3("111122233344455")

  1. 转义字符‌:

    • \:用于转义元字符,使其匹配自身。例如,\. 匹配点字符 .
  2. 字符类‌:

    • \d:匹配任意一个数字,相当于 [0-9]
    • \D:匹配任意一个非数字字符,相当于 [0-9]
    • \w:匹配任意一个字母、数字或下划线,相当于 [A-Za-z0-9_]
    • \W:匹配任意一个非字母、非数字或非下划线字符,相当于 [A-Za-z0-9_]
    • \s:匹配任意一个空白字符(包括空格、制表符、换行符等)。
    • \S:匹配任意一个非空白字符。
​
import re
s = '__ 0434p波野菠萝- %^&*'
re1 = re.findall('.',s)
print(re1)

re2 = re.findall(r'\d',s)
print(re2)

re3 = re.findall(r'\D',s)
print(re3)

re4 = re.findall(r'\w',s)
print(re4)

re5 = re.findall(r'\W',s)
print(re5)

re6 = re.findall(r'[_&]',s)
print(re6)

​
  1. 量词‌:

    • *?+???:非贪婪匹配,尽可能少地匹配字符。
    • {n,m}?:非贪婪匹配,匹配至少 n 次,但不超过 m 次,尽可能少地匹配。
  2. 断言‌:

    • ``:匹配字符串的开始(前面没有其他字符)。
    • $:匹配字符串的结束(后面没有其他字符)。
    • \b:匹配一个单词边界,即单词和空格之间的位置。
    • \B:匹配非单词边界的位置。
  3. 捕获与分组‌:

    • (pattern):捕获匹配 pattern 的子串。
    • (?:pattern):非捕获组,匹配 pattern 但不捕获。
import re

#匹配出163、126、qq邮箱
myemail = '[email protected]'
ret = re.match(r'^\w{4,20}@(163|126|qq)\.com$', myemail)
print(ret.group())

#匹配出<html><h1>www.bawei.com</h1></html>
ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", "<html><h1>www.hqyj.com</h1></html>")
print(ret.group())

#匹配出<html><h1>www.bawei.com</h1></html>
ret = re.match(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.hqyj.com</h1></html>")
print(ret.group())
  1. 替换与分组引用‌:

    • 在替换字符串中,\1\2 等表示捕获组的引用。

正则表达式具有强大的灵活性和表达能力,但也因此可能变得复杂和难以阅读。在编写正则表达式时,建议逐步构建和测试,以确保其正确性和性能

re.split函数

功能是分割

import re
s = 'user:zhangsan pwd:888666'
ret = re.split(r':| ', s)
print(ret)

re.sub函数

功能是替换

import re
s = 'i am zhangsan, i am 18 year, i like eat'
ret = re.sub(r"i", "I", s)
print(ret)


 

;