Python基础知识,Python大模型学习笔记

Python

安装Python:

# 下载源文件
wget https://www.python.org/ftp/python/3.12.6/Python-3.12.6.tgz

# 解压 
tar -zxvf Python-3.12.6.tgz
cd Python-3.12.6

# 编译
./configure --prefix=/root/training/Python-3.6.5
make
make install

# 添加环境变量
vim ~/.bashrc

# openssl
make  clean
./configure --prefix=/data/software/python3 --with-openssl=/data/software/openssl --with-openssl-rpath=auto

工具和镜像:

Pip:https://pip.pypa.io/en/stable/installation/

镜像地址:https://mirrors.huaweicloud.com/pythonhttps://registry.npmmirror.com/binary.html?path=python/3.11.4/

1.命令行

常用的 Python 3 命令行工具和选项:

  • python3,用途:运行 Python 脚本。python3 your_script.py。
  • -m,运行库模块作为脚本,python3 -m http.server 8000 启动一个简单的 HTTP 服务器。
  • -c,执行一段 Python 代码,python3 -c "print('Hello, World!')"。
  • -i,交互式解释器,执行完命令后保持交互模式,python3 -i。
  • -v,输出 Python 解释器启动时的版本和版权信息,python3 -v。
  • -V,输出 Python 解释器的版本,python3 -V。
  • -O,优化模式,移除文档字符串,python3 -O your_script.py。
  • -OO,进一步优化,移除文档字符串并进行一些优化,python3 -OO your_script.py。
  • -B,在执行前不写入 __pycache__ 目录,python3 -B your_script.py。
  • --check,检查源文件中的语法错误,python3 -m py_compile your_script.py。
  • -W,控制警告消息的显示,python3 -W all your_script.py。
  • -I,在交互模式下不导入 sys 和 site 模块,python3 -I。
  • -E,在执行前忽略环境变量,python3 -E your_script.py。
  • -x,在执行前忽略源文件编码声明,python3 -x your_script.py。
  • -u,强制 Python 以非缓冲的方式运行,python3 -u your_script.py。
  • -S,在执行前不导入 site.py,python3 -S your_script.py。
  • -R,在执行前不运行 site.py 中的 site.main(),python3 -R your_script.py。
  • -E,在执行前不设置 PYTHON* 环境变量,python3 -E your_script.py。
  • -X,启用或禁用特定的警告,python3 -X faulthandler your_script.py。
  • --help,显示命令行选项的帮助信息,python3 --help。

2.基础知识

Python 中有一些全局常量和变量,它们是内置的,可以在任何地方使用,而不需要导入任何模块。

常量:

  • True:布尔类型中的真值。
  • False:布尔类型中的假值。
  • None:表示空值或无值的状态。

内置类型:

  • bool:布尔类型。
  • int:整数类型。
  • float:浮点数类型。
  • complex:复数类型。
  • str:字符串类型。
  • list:列表类型。
  • tuple:元组类型。
  • dict:字典类型。
  • set:集合类型。
  • frozenset:不可变集合类型。
  • bytes:字节串类型。
  • bytearray:可变字节串类型。
  • memoryview:内存视图类型。

内置函数:

  • abs():绝对值。
  • all():判断给定的可迭代参数 iterable 中的所有元素是否都为 True。
  • any():判断给定的可迭代参数 iterable 中是否至少有一个元素为 True。
  • ascii():返回对象的 ASCII 表示。
  • bin():返回整数的二进制表示。
  • bool():将值转换为布尔类型。
  • bytearray():返回可变的字节串。
  • bytes():返回不可变的字节串。
  • callable():判断对象是否可调用。
  • chr():将 ASCII 码转为对应的字符。
  • classmethod():创建一个类方法。
  • compile():编译源代码为可执行的代码或字节码。
  • complex():返回一个复数。
  • delattr():删除对象的属性。
  • dict():返回一个新的字典。
  • dir():返回对象的属性列表。
  • divmod():返回商和余数。
  • enumerate():返回枚举对象,结合索引和元素。
  • eval():执行字符串中的 Python 表达式。
  • exec():执行字符串中的 Python 代码。
  • filter():过滤序列,过滤掉不符合条件的元素。
  • float():将值转换为浮点数。
  • format():格式化字符串。
  • frozenset():返回一个不可变集合。
  • getattr():获取对象的属性。
  • globals():返回当前全局符号表的字典。
  • hasattr():判断对象是否有指定的属性。
  • hash():返回对象的哈希值。
  • help():返回对象的帮助文档。
  • hex():返回整数的十六进制表示。
  • id():返回对象的唯一标识符。
  • input():获取用户输入。
  • int():将值转换为整数。
  • isinstance():判断对象是否是给定类型的实例。
  • issubclass():判断一个类是否是另一个类的子类。
  • iter():返回对象的迭代器。
  • len():返回对象的长度。
  • list():返回一个新的列表。
  • locals():返回当前局部符号表的字典。
  • map():对序列的每个元素应用函数。
  • max():返回最大值。
  • memoryview():返回内存视图。
  • min():返回最小值。
  • next():返回迭代器的下一个元素。
  • object():返回一个新对象。
  • oct():返回整数的八进制表示。
  • open():打开文件。
  • ord():返回字符的 ASCII 码。
  • pow():返回 x 的 y 次幂。
  • print():打印输出。
  • property():创建一个属性。
  • range():返回一个整数序列。
  • repr():返回对象的官方字符串表示。
  • reversed():反转序列。
  • round():四舍五入。
  • set():返回一个新的集合。
  • setattr():设置对象的属性。
  • slice():返回一个切片对象。
  • sorted():返回排序后的列表。
  • staticmethod():创建一个静态方法。
  • str():将值转换为字符串。
  • sum():返回序列的总和。
  • super():返回对象的父类。
  • tuple():返回一个新的元组。
  • type():返回对象的类型。
  • vars():返回对象的 dict 属性。
  • zip():将多个迭代器压缩在一起。

内置异常:

  • BaseException:所有内置异常的基类。
  • Exception:常规异常的基类。
  • ArithmeticError:所有算术错误异常的基类。
  • AssertionError:断言错误。
  • AttributeError:属性错误。
  • EOFError:文件结束错误。
  • FloatingPointError:浮点错误。
  • GeneratorExit:生成器退出异常。
  • ImportError:导入模块失败。
  • IndentationError:缩进错误。
  • IndexError:索引错误。
  • KeyError:键错误。
  • KeyboardInterrupt:键盘中断。
  • LookupError:查找错误。
  • MemoryError:内存错误。
  • NameError:名称错误。
  • NotImplementedError:未实现错误。
  • OSError:操作系统错误。
  • OverflowError:溢出错误。
  • RecursionError:递归错误。
  • ReferenceError:引用错误。
  • RuntimeError:运行时错误。
  • StopIteration:停止迭代。
  • SyntaxError:语法错误。
  • SystemError:系统错误。
  • SystemExit:系统退出。
  • TypeError:类型错误。
  • ValueError:值错误。
  • ZeroDivisionError:除零错误。

内置模块:

  • __name__:当前模块的名称。
  • __file__:当前模块的文件路径。
  • __builtins__:内置函数和变量的字典。
常量
在Python中,虽然没有专门的语法来声明常量,但按照惯例,常量名称通常使用全大写字母来表示。在Python中,任何不可变的数据类型都可以用来作为字典(map)的键。由于常量通常是不变的,所以它们可以作为字典的键。

3.基本语法

三元运算:

# 三元运算符
max_num = num1 if num1 >= num2 else num2

base_path = (
    user_path
    / format_file_name(kwargs.get("naming", "{create}_{desc}"), aweme_data_dict)
    if kwargs.get("folderize")
    else user_path
)

条件语句:使用 if, elif, else 进行条件判断。

if x > 0:
    print("Positive")
elif x == 0:
    print("Zero")
else:
    print("Negative")

循环:for 循环用于遍历序列(如列表、元组、字典等),while 循环用于在满足条件时重复执行代码块。

range() 函数在 Python 中返回的是一个 range 类型的对象。range 类型是一个不可变的序列,它提供了一种高效的方式来迭代一系列数字。range() 函数有三个参数:start(起始值,默认为 0),stop(结束值,不包含此值),和 step(步长,默认为 1)。你可以使用 step 参数来指定步长。

# for循环
for i in range(5):
    print(i)

# while循环
counter = 0
while counter < 5:
    print("counter 的值为:", counter)
    counter += 1  # 等同于 counter = counter + 1
提示
在 Python 中,break 语句只能用来退出最内层的循环。与某些其他编程语言不同,Python 不支持直接使用标签或指定层级来跳出多层嵌套循环。

遍历元组:

my_tuple = (1, 2, 3, 4, 5)

# 直接遍历
for item in my_tuple:
    print(item)

# 使用 enumerate() 遍历索引和元素
for index, item in enumerate(my_tuple):
    print(index, item)

遍历列表:

my_list = [1, 2, 3, 4, 5]

# 直接遍历
for item in my_list:
    print(item)

# 使用 enumerate() 遍历索引和元素
for index, item in enumerate(my_list):
    print(index, item)

遍历字典:

my_dict = {'a': 1, 'b': 2, 'c': 3}

# 遍历键
for key in my_dict:
    print(key)

# 遍历值
for value in my_dict.values():
    print(value)

# 遍历键值对
for key, value in my_dict.items():
    print(key, value)

4.异常和错误处理

在 Python 中,异常处理是通过使用 try 和 except 语句来实现的。

try:
    result = 10 / 0
    raise ValueError("这是一个错误")
except ExceptionType1:
    # 处理 ExceptionType1 的代码块
    pass
except (ExceptionType2, ExceptionType3) as e:
    # 同时处理 ExceptionType2 和 ExceptionType3 的代码块
    print(e)
except ZeroDivisionError:
    print("不能除以零!")
    raise  # 重新抛出当前捕获的异常
except ZeroDivisionError:
    print("不能除以零!")
    raise  # 重新抛出当前捕获的异常
except Exception as e:
    print(f"发生了异常:{e}")
    raise  # 抛出新的异常或重新抛出当前捕获的异常
else:
    print("没有异常发生")
finally:
    print("这是 finally 块,总是被执行")

5.字符串操作

创建字符串:

s1 = 'Hello, World!'
s2 = "Hello, World!"
s3 = '''Hello,
World!'''
s4 = """Hello,
World!"""

字符串连接:

greeting = "Hello, "
name = "World"
message = greeting + name + "!"
print(message)  # 输出:Hello, World!

字符串重复:

repeated = "hello " * 3
print(repeated)  # 输出:hello hello hello

字符串切片:

s = "Hello, World!"
print(s[0:5])  # 输出:Hello
print(s[7:])   # 输出:World!

字符串方法:

  • .upper():转换为大写。
  • .lower():转换为小写。
  • .capitalize():首字母大写。
  • .title():每个单词的首字母大写。
  • .strip():移除字符串开头和结尾的空白字符。
  • .split():按照指定分隔符切分字符串。
  • .join():将序列中的元素以指定的字符连接生成一个新的字符串。
  • .find() 或 .index():查找子字符串并返回索引位置。
  • .replace():替换字符串中的某些字符。
  • .len():返回字符串长度。

字符串格式化:

name = "World"
greeting = "Hello, %s!" % name
print(greeting)  # 输出:Hello, World!

greeting = "Hello, {}!".format(name)
print(greeting)  # 输出:Hello, World!

greeting = f"Hello, {name}!"
print(greeting)  # 输出:Hello, World!

字符串编码:

s = "Hello, World!"
encoded = s.encode('utf-8')  # 编码为字节串
decoded = encoded.decode('utf-8')  # 解码为字符串

字符串前缀:

  • f或 F:表示格式化字符串字面量(f-string),允许在字符串中直接嵌入表达式。
  • r 或 R:表示原始字符串,忽略字符串中的转义字符。
  • b 或 B:表示字节字符串,用于处理二进制数据。

6.模块和包

Python 模块是包含 Python 代码的文件,通常是一个 .py 文件。模块可以定义函数、类和变量,也可以包含可执行的代码。

# 导入模块
import mymodule
mymodule.greet("Alice")

# 导入特定的功能
from mymodule import greet, Calculator

greet("Bob")
calculator = Calculator()

# 使用别名
import mymodule as mm
mm.greet("Charlie")

包是包含多个模块的目录,它必须包含一个名为 __init__.py 的文件(可以为空),该文件标识该目录为 Python 包。

mypackage/
│
├── __init__.py
├── module1.py
└── module2.py

引入包中的模块:

# 包中指定的模块
from mypackage import module1
module1.foo() 

# 这样引入,每次使用都得指定全名
import e.e1.module_1

# 引入子包
from e.e1 import module_1 
module_1.func_1()

# 相对导入
from . import module_1
访问权限
公共成员是模块的一部分,可以被模块外部的代码访问和使用。在 Python 中,任何不在变量名、函数名或类名前加前缀 _ 的成员都被认为是公共的。

7.元组、列表、字典

元组是一个不可变的序列,一旦创建就不能被修改。

# 创建
my_tuple = (1, 2, 3)
empty_tuple = ()

# 访问
print(my_tuple[1])  # 输出:2

# 切片
print(my_tuple[1:3])  # 输出:(2, 3)

# 解包
a, b, c = my_tuple

列表是一个可变的序列,可以修改、添加或删除其中的元素。

# 创建
my_list = [1, 2, 3]
empty_list = []

# 访问
print(my_list[1])  # 输出:2

# 切片
print(my_list[1:3])  # 输出:[2, 3]

# 添加
my_list.append(4)

# 删除
my_list.remove(2)
last_item = my_list.pop()

字典是一个无序的键值对集合,键必须是不可变类型,如字符串或元组。

# 创建
my_dict = {'name': 'Alice', 'age': 25}
empty_dict = {}

# 访问
print(my_dict['name'])  # 输出:Alice

#删除
del my_dict['age']
removed_item = my_dict.pop('gender')

集合(Set)是一个无序的、不包含重复元素的集合。它类似于数学中的集合概念,可以进行数学上的集合运算,如并集、交集、差集等。集合是一个可变的数据类型,其元素是唯一的。

# 创建
my_set = {1, 2, 3}
my_set = set([1, 2, 3])

# 使用大括号 {} 创建空集合是无效的,因为空集在 Python 中用 set() 函数表示。

# 添加元素
my_set.add(4)

# 删除元素
my_set.remove(2)
my_set.discard(5)  # 即使 5 不存在,也不会报错

# 清空集合
my_set.clear()

# 是否存在
print(3 in my_set)  # 输出:True

# 集合的大小
print(len(my_set))

# 交集
set1 = {1, 2, 3}
set2 = {3, 4, 5}
union_set = set1.union(set2)  # 或者 set1 | set2

# 差集
difference_set = set1.difference(set2)  # 或者 set1 - set2

推导式(Comprehension)是 Python 中的一种语法结构,它提供了一种简洁的方式来创建列表、字典、集合等数据结构。

# 列表推导式
[expression for item in iterable if condition]

squares = [x**2 for x in range(10)]
print(squares)  # 输出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  • expression:对每个元素进行的操作。
  • item:从 iterable 中依次取出的元素。
  • iterable:一个序列、集合或其他迭代器。
  • condition(可选):一个布尔表达式,只有满足条件的元素才会被包括在内。
# 字典推导式
{key_expression: value_expression for item in iterable if condition}

squares_dict = {x: x**2 for x in range(10)}
print(squares_dict)  # 输出:{0: 0, 1: 1, 2: 4, 3: 9, ...}
  • key_expression:字典的键。
  • value_expression:字典的值。

8.函数

闭包是在一个函数内部定义的另一个函数,内部函数引用了外部函数的变量。在外部函数返回内部函数时,会形成一个闭包,因为内部函数携带了外部函数的上下文,即使外部函数已经执行完毕。

def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

# 创建一个闭包
closure = outer_function(2)

# 使用闭包
print(closure(3))  # 输出:5

函数内使用外部变量:

x = 10  # 全局变量

def my_function():
    y = 5  # 局部变量
    print(x)  # 可以访问全局变量

my_function()

在 Python 中,所有的参数传递都是按引用传递。然而,由于 Python 中的数字、字符串和元组等是不可变类型,所以当它们作为参数传递给函数时,表现得像是按值传递。

  • 不可变类型(按值传递):如果参数是不可变类型,对参数的修改不会影响原始数据。
  • 可变类型(按引用传递):如果参数是可变类型(如列表、字典等),则可以在函数内部修改它们,并且这些修改会影响到原始数据。
global
在函数外部定义的变量默认是全局变量,但在函数内部定义的变量默认是局部变量。如果你想在函数内部修改全局变量,你需要使用 global 关键字来声明。

函数参数可以通过多种方式传递给函数。以下是一些常见的参数传递方式:

# 位置参数
def func(a, b, c):
    print(a, b, c)

func(1, 2, 3)  # 输出: 1 2 3

# 关键字参数
def func(a, b, c):
    print(a, b, c)

func(a=1, b=2, c=3)  # 输出: 1 2 3
func(c=3, a=1, b=2)  # 输出: 1 2 3

# 默认参数
def func(a, b, c=0):
    print(a, b, c)

func(1, 2)        # 输出: 1 2 0
func(1, 2, 3)     # 输出: 1 2 3

# 可变参数
def func(*args):
    for arg in args:
        print(arg, end=' ')

func(1, 2, 3)  # 输出: 1 2 3

# 关键字可变参数
def func(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

func(a=1, b=2, c=3)  # 输出: a: 1 b: 2 c: 3

9.面向对象

Python 是一种支持面向对象编程(Object-Oriented Programming, OOP)的高级编程语言。面向对象编程是一种编程范式,它使用“对象”来设计应用程序和程序的结构。

类(Class):

  • 类是创建对象的模板或蓝图。它定义了一组属性(变量)和方法(函数)。
  • 类可以包含构造器(__init__),这是一个特殊的方法,当创建类的新实例时会自动调用。
class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model

对象(Object):

  • 对象是类的实例。创建类的新实例时,会创建一个对象。
  • 对象可以接收数据(即类的属性)和执行操作(即类的方法)。
my_car = Car("Toyota", "Corolla")

继承(Inheritance):

  • 继承是一种创建新类的方式,新类可以从现有类中继承属性和方法。
  • 子类(派生类)继承父类(基类)的特性,并可以添加或覆盖它们。
class ElectricCar(Car):
    def __init__(self, make, model, battery_size):
        super().__init__(make, model)
        self.battery_size = battery_size

封装(Encapsulation):

  • 封装是将数据(属性)和代码(方法)捆绑在一起的过程,并对对象的某些部分隐藏起来,只暴露有限的接口。
  • 在 Python 中,可以通过在属性名前加双下划线(__)来实现属性的私有化。
class Car:
    def __init__(self, make, model):
        self.__make = make
        self.__model = model

多态(Polymorphism):

  • 多态性是指允许不同类的对象对同一消息做出响应的能力,即同一个接口,使用不同的实例而执行不同操作。
  • 在 Python 中,多态可以通过方法重载和重写来实现。
class Car:
    def start(self):
        print("Car is starting")

class ElectricCar(Car):
    def start(self):
        print("Electric Car is starting with no noise")

属性(Attributes):

  • 属性是对象的状态信息,即对象的变量。
  • 属性可以是公有的,也可以是私有的。

方法(Methods):

  • 方法是对象的行为,即对象可以执行的操作。
  • 方法通常用来修改对象的状态或执行与对象相关的操作。

类变量和实例变量:

  • 类变量是定义在类中的变量,所有实例共享同一个类变量。
  • 实例变量是定义在方法中的变量,每个实例都有自己的实例变量。

类方法和静态方法:

  • 类方法不接收隐式的 self 参数,而是接收 cls 作为第一个参数,它是属于类的,而不是实例的。
  • 静态方法不接收 self 或 cls 参数,它们可以不依赖于对象或类直接被调用。

特殊方法:

  • __init__(self, ...): 类的构造器,当一个实例被创建时调用。
  • __del__(self): 类的析构器,当一个实例被销毁时调用。
  • __call__(self, ...): 允许一个实例像函数那样被调用。
  • __getitem__(self, key): 获取序列的元素,如 obj[key]。
  • __setitem__(self, key, value): 设置序列的元素,如 obj[key] = value。
  • __delitem__(self, key): 删除序列的元素,如 del obj[key]。
  • __len__(self): 返回容器中元素的数量,如 len(obj)。
  • __iter__(self): 返回对象的迭代器,用于迭代操作,如 for x in obj。
  • __next__(self): 返回迭代器的下一个元素。
  • __repr__(self): 返回对象的“官方”字符串表示,通常用于调试。
  • __str__(self): 返回对象的“非官方”字符串表示,用于打印。
  • __bytes__(self): 返回对象的字节串表示。
  • __format__(self, format_spec): 定义对象的格式化字符串表示。
  • __lt__(self, other), __le__(self, other), __eq__(self, other), __ne__(self, other), __gt__(self, other), __ge__(self, other): 定义对象的比较操作。
  • __hash__(self): 返回对象的哈希值。
  • __bool__(self): 定义布尔值测试。
  • __getattr__(self, name): 当访问一个不存在的属性时调用。
  • __setattr__(self, name, value): 当设置一个属性的值时调用。
  • __delattr__(self, name): 当删除一个属性时调用。
  • __getattribute__(self, name): 在访问属性之前调用,可以重写以拦截属性访问。
  • __dir__(self): 返回对象的属性目录。
  • __enter__(self), __exit__(self, exc_type, exc_value, traceback): 用于定义上下文管理器,如 with obj。
  • __copy__(self), __deepcopy__(self, memo): 用于定义对象的浅拷贝和深拷贝行为。
  • __new__(cls, ...): 创建并返回类的新实例。

10.多线程

Python 多线程是指在 Python 程序中同时运行多个线程的能力。线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。Python 提供了 threading 模块来支持多线程编程。

  • threading.Thread 类:用于创建线程。可以通过继承 Thread 类并重写其 run() 方法来定义线程任务。
    start() 方法:启动线程。必须在 Thread 实例上调用此方法以开始线程的执行。
  • join() 方法:阻塞调用它的线程,直到线程终止。这通常用于等待线程完成其任务。
  • is_alive() 方法:返回线程是否仍然存活(即正在运行或等待)。
  • getName() 方法:返回线程的名称。
  • setName() 方法:设置线程的名称。
  • current_thread() 函数:返回当前线程的 Thread 实例。
  • enumerate() 函数:返回一个列表,包含当前活动的线程。
  • active_count() 函数:返回当前活动线程的数量。
  • Lock 类:用于线程同步的锁。可以用于保护共享资源,避免竞争条件。
  • RLock 类:可重入锁。它允许同一个线程多次获得锁。
  • Semaphore 类:信号量。用于限制对共享资源的访问数量。
  • BoundedSemaphore 类:有界信号量。与 Semaphore 类似,但初始化时需要指定一个最大值。
  • Event 类:事件。用于线程间的通信,允许一个线程通知其他线程某个事件已经发生。
  • Condition 类:条件变量。用于复杂的线程同步,允许一个或多个线程等待,直到被另一个线程通知。
  • Barrier 类:屏障。用于多线程同步,使得一组线程相互等待,直到到达某个共同点。
  • Timer 类:计时器。在指定的时间后执行一个函数。
  • local 和 stack_local 类:用于创建线程局部数据。
  • ThreadError 异常:当线程操作出错时抛出的异常。
  • settrace() 函数:设置一个全局的线程追踪函数。
  • setprofile() 函数:设置一个全局的线程分析函数。

常用示例:

import threading

class MyThread(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run(self):
        print(f"Thread {self.name} is running")

# 创建线程
t1 = MyThread(name="Thread-1")
t2 = MyThread(name="Thread-2")

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

线程同步是确保多个线程在访问共享资源时避免数据不一致和竞态条件的重要机制。Python 提供了多种同步原语,如锁(Lock)、事件(Event)、条件(Condition)和信号量(Semaphore)等。

锁(Lock),锁是最基本的同步原语,用于确保同一时间只有一个线程可以执行某个代码段:

# 创建锁
import threading
lock = threading.Lock()

# 使用 .acquire() 方法获取锁。如果锁已被其他线程获取,则当前线程将阻塞,直到锁被释放。
lock.acquire()

# 释放锁
lock.release()

# Lock 对象可以作为上下文管理器使用,确保在离开代码块时自动释放锁
with lock:
    # 执行临界区代码
    pass

# 尝试获取锁,如果锁已经被其他线程获取,则立即返回 False 而不是等待。
if lock.try_acquire():
    try:
        # 执行临界区代码
        pass
    finally:
        lock.release()

# .acquire(timeout=...) 方法可以设置超时时间,如果在指定的时间内无法获取锁,则抛出 TimeoutError。
try:
    lock.acquire(timeout=5)
except threading.TimeoutError:
    print("Could not acquire lock within the timeout period")

Event(事件) ,事件用于线程之间的通信,一个线程可以等待事件被另一个线程设置:

import threading

event = threading.Event()

def waiter():
    event.wait()
    print("Event is set")

def setter():
    print("Waiting for 5 seconds...")
    threading.sleep(5)
    event.set()

t1 = threading.Thread(target=waiter)
t2 = threading.Thread(target=setter)

t1.start()
t2.start()

t1.join()
t2.join()

Condition,条件变量用于复杂的线程同步,允许一个或多个线程等待,直到被另一个线程通知:

import threading

c = threading.Condition()

def consumer():
    with c:
        print("Consumer is waiting for data")
        c.wait()
        print("Consumer received data")

def producer():
    with c:
        print("Producer is producing data")
        c.notify()
        print("Data produced")

t1 = threading.Thread(target=consumer)
t2 = threading.Thread(target=producer)

t1.start()
t2.start()

t1.join()
t2.join()

11.with语句

with 语句在 Python 中是一种语法结构,它用于包裹执行代码块,以确保资源的正确管理,特别是在处理文件操作、线程锁和其他需要设置和清除资源的场合。

  • 当执行到 with 语句时,Python 会调用上下文管理器的 __enter__ 方法,并且通常会将 __enter__ 方法的返回值赋值给 as 后面的变量。
  • 执行 with 代码块内的代码。
  • 代码块执行完成后,无论是否发生异常,都会调用上下文管理器的 __exit__ 方法。如果发生异常,__exit__ 方法的参数会接收到异常的类型、值和 traceback 对象,否则这些参数都是 None。
# 文件操作
with open('file.txt', 'r') as file:
    data = file.read()
    # 文件会在此处自动关闭

# 线程锁
lock = threading.Lock()
with lock:
    # 执行临界区代码
    pass
# 锁会在此处自动释放

# 上下文管理器
class ManagedResource:
    def __enter__(self):
        print("Entering context.")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting context.")
        # 可以在这里处理异常
with ManagedResource() as resource:
    # 使用资源
    pass

12. asyncio  

在 Python 3.4 版本中,asyncio 模块被引入作为标准库,提供了异步编程的支持。

从 Python 3.5 开始,async 和 await 关键字被引入,使得编写异步代码更加直观和简洁。

Python 3.7 版本进一步优化了 asyncio,引入了 asyncio.run() 这样的高级方法,让编写和管理异步程序变得更加简单。

事件循环(Event Loop):

  • 事件循环是 asyncio 的核心,它不断地执行事件和任务,直到没有更多的事件和任务为止。
  • 事件循环负责调度协程,处理 I/O 事件,执行回调函数等。
# 在函数定义前加上 async 关键字定义异步函数
import asyncio

async def say_after(delay, what):
    await asyncio.sleep(delay)  # 模拟异步操作,比如网络请求
    print(what)

# 使用 asyncio.run() 来运行主异步函数
asyncio.run(say_after(1, 'hello'))

# 异步的主函数,它调度多个异步任务
async def main():
    await say_after(1, 'hello')
    await say_after(2, 'world')

# 并发运行多个异步任务,并等待它们全部完成
async def main():
    # 并发运行多个异步任务
    await asyncio.gather(
        say_after(1, 'hello'),
        say_after(2, 'world')
    )

asyncio.run(main())

# 创建任务(Task)来并发运行协程。任务是协程的执行单元。
async def main():
    # 创建任务
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))

    # 等待任务完成
    await task1
    await task2

asyncio.run(main())

# 为异步操作设置超时,或者取消正在运行的任务。
async def main():
    try:
        # 设置超时
        await asyncio.wait_for(say_after(10, 'this takes too long'), timeout=5)
    except asyncio.TimeoutError:
        print('Timeout occurred!')

asyncio.run(main())

# 取消任务
async def main():
    task = asyncio.create_task(say_after(10, 'this will be cancelled'))
    await asyncio.sleep(2)
    task.cancel()
    try:
        await task
    except asyncio.CancelledError:
        print('Task was cancelled')

asyncio.run(main())

# 在异步函数中使用 try/except 块来捕获和处理异常
async def main():
    try:
        await say_after(1, 'this will raise an exception')
    except Exception as e:
        print(f'An error occurred: {e}')

asyncio.run(main())

13. json处理

Python数据转Json:

import json

# 一个 Python 字典
data = {
    "name": "John",
    "age": 30,
    "city": "New York"
}

# 输出到文件
json_str = json.dump(data, file)

# 转换为 JSON 字符串
json_str = json.dumps(data)

Json转字典:

import json

# 一个 JSON 字符串
json_str = '{"name": "John", "age": 30, "city": "New York"}'

# 解析为 Python 字典
data = json.loads(json_str)

14.日期与时间

datetime 模块是 Python 标准库中处理日期和时间的核心模块。它提供了以下类:

  • datetime.date:表示日期(年、月、日)。
  • datetime.time:表示时间(时、分、秒、微秒)。
  • datetime.datetime:表示日期和时间。
  • datetime.timedelta:表示两个日期或时间之间的差异。
  • datetime.tzinfo:所有时区信息类的基类。
  • datetime.timezone:用于表示固定时区偏移量的类。

常用函数和方法

  • date.today():返回当前本地日期。
  • datetime.now():返回当前日期和时间。
  • datetime.utcnow():返回当前的 UTC 日期和时间。
  • datetime.combine(date, time):将日期和时间合并为一个 datetime 对象。
  • datetime.strptime(date_string, format):根据指定的格式将字符串解析为 datetime 对象。
  • datetime.strftime(format):将 datetime 对象格式化为字符串。

time 模块提供了各种与时间相关的函数,主要用于处理时间戳。

  • time.time():返回当前时间的时间戳。
  • time.sleep(seconds):暂停执行指定的秒数。
  • time.localtime([secs]):根据给定的时间戳返回本地时间的 struct_time 对象。
  • time.gmtime([secs]):根据给定的时间戳返回 UTC 时间的 struct_time 对象。
  • time.mktime(tuple):将 struct_time 对象转换为时间戳。

calendar 模块提供了生成日历的功能和一些与日历相关的函数。

  • calendar.month(year, month):返回一个多行字符串,显示一个月的日历。
  • calendar.monthcalendar(year, month):返回一个列表,包含一个月中的每一天是星期几。
  • calendar.monthrange(year, month):返回一个月的第一天是星期几和该月的天数。
from datetime import datetime

# 获取当前日期和时间
now = datetime.now()

# 格式化日期和时间
formatted_date = now.strftime("%Y-%m-%d %H:%M:%S")
print("格式化后的日期和时间:", formatted_date)

# 时间戳格式化输出

import time
from datetime import datetime

# 获取当前时间的时间戳
timestamp = time.time()

# 将时间戳转换为日期时间对象
dt_object = datetime.fromtimestamp(timestamp)
print("时间戳转日期时间:", dt_object)

# 也可以使用 utcfromtimestamp() 来获取 UTC 时间
dt_utc = datetime.utcfromtimestamp(timestamp)
print("UTC 时间戳转日期时间:", dt_utc)

# 字符串转时间戳

from datetime import datetime

# 日期时间字符串
date_string = "2024-05-29 12:30:45"

# 将字符串解析为日期时间对象
dt_object = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S")

# 将日期时间对象转换为时间戳
timestamp = dt_object.timestamp()
print("字符串转时间戳:", timestamp)

15.获取指定数据的类型

# 获取不同类型的数据类型
number = 10
string = "Hello, World!"
list_data = [1, 2, 3]
dict_data = {'key': 'value'}
tuple_data = (1, 2, 3)
set_data = {1, 2, 3}
frozenset_data = frozenset([1, 2, 3])
bool_value = True

# 使用 type() 函数获取类型
print(type(number))          # <class 'int'>
print(type(string))          # <class 'str'>
print(type(list_data))       # <class 'list'>
print(type(dict_data))       # <class 'dict'>
print(type(tuple_data))      # <class 'tuple'>
print(type(set_data))        # <class 'set'>
print(type(frozenset_data))  # <class 'frozenset'>
print(type(bool_value))      # <class 'bool'>

16.文件和目录

  • os.remove(file),删除指定文件
  • os.listdir(path): 列出指定路径下的所有文件和目录名。
  • os.mkdir(path): 创建一个新目录。
  • os.makedirs(path): 创建新目录,如果中间的目录不存在也会一并创建。
  • os.rmdir(path): 删除一个空目录。
  • os.removedirs(path): 删除目录及其所有内容。
  • os.path.exists(path): 检查指定路径是否存在。
  • os.path.isfile(path): 检查指定路径是否为文件。
  • os.path.isdir(path): 检查指定路径是否为目录。
  • os.path.join(path, *paths): 将多个路径组合成一个路径。
  • os.path.getsize(path): 获取文件的大小。
  • os.path.basename(path): 获取路径的基本名称。
  • os.path.dirname(path): 获取路径的目录名称。
  • os.rename(src, dst): 重命名文件或目录。

17.正则

Python 中的正则表达式(Regular Expressions,简称 regex)是通过一些特殊字符组成的模式,用于匹配字符串中的字符组合。正则表达式在 Python 中通过内置的 re 模块提供支持

import re

# match 从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
match_result = re.match(r'^(d{4})-(d{2})-(d{2})$', '2023-11-15')  # 匹配日期格式
if match_result:
    print("Match:", match_result.groups())

# search 扫描整个字符串,并返回第一个成功的匹配。
search_result = re.search(r'^(d{4})-(d{2})-(d{2})$', '15-11-2023 is not a date')  # 搜索日期格式
if search_result:
    print("Search:", search_result.groups())

# findall 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表。
all_matches = re.findall(r'bw+b', 'The rain in Spain')  # 找出所有单词
print("Find all:", all_matches)

# finditer 与 findall() 类似,返回一个迭代器,迭代器的每个元素都是一个 Match 对象。
all_matches_iter = re.finditer(r'bw+b', 'The rain in Spain')
for match in all_matches_iter:
    print("Find iter:", match.group())

# sub 替换字符串中的某些部分。
replaced_text = re.sub(r'bw+b', 'word', 'The rain in Spain')  # 替换所有单词为'word'
print("Replaced text:", replaced_text)

# subn 替换字符串中的某些部分,并返回替换的次数。
replaced_text_and_count = re.subn(r'bw+b', 'word', 'The rain in Spain')
print("Replaced text and count:", replaced_text_and_count)

# split 按照能够匹配的子串将字符串分割后返回列表。
split_text = re.split(r's+', 'The rain in Spain')  # 使用一个或多个空格分割字符串
print("Split text:", split_text)

# compile 用于编译正则表达式,生成一个正则表达式( Pattern )对象,供其他方法使用。
pattern = re.compile(r'bw+b')
match_result = pattern.match('The rain in Spain')
print("Compiled match:", match_result.group())

# escape 用于对字符串中所有可能被解释为正则运算符的字符进行转义。
escaped_string = re.escape('https://example.com?search=Python regular expressions')
print("Escaped string:", escaped_string)

# purge 清除正则表达式缓存。
re.purge()

Pip使用方法

1.基础命令

相关地址:https://mirrors4.tuna.tsinghua.edu.cn/help/pypi/

pip和pip3的区别
pip 和 pip3 都是 Python 的包管理工具,用于安装和管理 Python 包。它们的主要区别在于它们默认关联的 Python 版本。

相关命令:

# 安装最新的包
pip3 install package_name

# 安装指定版本的包
pip3 install package_name==version

# 卸载包
pip3 uninstall package_name

# 安装指定文件内的包
pip install -r requirements.txt 

# 查看已安装
pip3 list

# 查看指定包的安装信息
pip3 show funasr

2.其它包管理

PDM:https://github.com/pdm-project/pdm

PipEnv:https://pipenv.pypa.io/en/latest/

Python虚拟环境(venv)

Python虚拟环境是一个独立的Python解释器和库的副本。它允许您在不影响系统全局Python安装的情况下安装和管理项目特定的包。

1.创建虚拟环境

# 建一个名为venv的虚拟环境
python3 -m venv venv

这将在项目目录中创建一个名为venv的文件夹,其中包含您的虚拟环境。您可以将该文件夹命名为其他名称,但通常将其命名为venv是一个很好的做法。

2.激活虚拟环境

激活虚拟环境将确保您在该环境中安装的包和运行的Python命令是隔离的。

# 在Unix或macOS上
source venv/bin/activate

# 在Windows上
.venv/Scripts/activate

# 激活虚拟环境后,您的终端或命令提示符将显示虚拟环境的名称
(venv) $

3.退出虚拟环境

# 退出虚拟环境
deactivate

Flask 

中文文档:https://dormousehole.readthedocs.io/en/latest/index.html

1.request

  • request.args:一个不可变的 MultiDict 类型,包含了 URL 查询字符串参数。例如,对于请求 ?key=value,可以通过 request.args.get('key') 来获取值。
  • request.form:一个不可变的 MultiDict 类型,包含了表单数据(通常是 POST 请求中的数据)。可以通过 request.form.get('key') 来获取特定的表单字段。
  • request.json:如果请求的内容类型是 application/json,那么 request.json 将是一个解析后的对象(通常是字典或列表),包含 JSON 数据。
  • request.headers:一个不可变的 EnvironHeaders 类型,包含了 HTTP 请求头。例如,request.headers.get('Content-Type') 可以获取内容类型。
  • request.cookies:一个不可变的 MultiDict 类型,包含了 HTTP cookies。
  • request.files:一个不可变的 ImmutableMultiDict 类型,包含了上传的文件。可以通过 request.files.get('file') 来获取特定的文件对象。
  • request.data:包含请求体的数据,通常是 POST 请求的数据。默认情况下,它是一个字节字符串,但你可以使用 request.data.decode() 将其解码为字符串。
  • request.method:表示请求使用的 HTTP 方法(如 GET, POST, PUT, DELETE 等)。
  • request.path:请求的路径部分,例如 /home.
  • request.url:完整的请求 URL。
  • request.base_url:包含 URL 的基础部分(包括域名和端口,如果有的话),但不包括查询字符串。
  • request.host:请求的主机名,例如 example.com.
  • request.host_url:主机名和请求路径的组合,例如 http://example.com/home.
  • request.script_root:与 request.path 相同,通常用于重定向。
  • request.url_root:与 request.base_url 相同,通常用于重定向。
  • request.referrer:表示引用请求的页面 URL(即 HTTP Referer 头部的值)。
  • request.remote_addr:发出请求的客户端 IP 地址。
  • request.is_xhr:一个布尔值,表示请求是否由一个 Ajax 请求发出(通过检查 X-Requested-With 请求头)。
  • request.access_route:包含客户端到服务器的路由列表。
  • request.scheme:请求使用的协议,通常是 http 或 https。

要使用 request 对象,你需要从 flask 模块中导入它:

from flask import request

@app.route('/some-path', methods=['POST'])
def some_function():
    user_id = request.form.get('user_id')
    content_type = request.headers.get('Content-Type')
    is_ajax = request.is_xhr
    # ... 其他操作

2.response

  • response.data:设置响应体的内容。这是一个字符串属性,你可以赋予它任何想要返回给客户端的数据。
  • response.status_code:设置 HTTP 状态码。例如,200 表示成功,404 表示未找到。
  • response.headers:一个字典对象,用于设置响应头。你可以添加、修改或删除头部字段。
  • response.mimetype:设置响应的内容类型(MIME 类型)。默认通常是 text/html,但你可以更改它,比如设置为 application/json。
  • response.location:设置 HTTP 头中的 Location 字段,通常用于重定向。
  • response.charset:设置响应编码。默认是 utf-8。
  • response.cookies:一个字典对象,用于设置客户端的 cookies。
  • response.set_cookie(key, value, expires=None, max_age=None, domain=None, path=None, secure=None, httponly=None, samesite=None):用于设置一个 cookie。你可以指定 expires、max_age、domain、path、secure、httponly 和 samesite 等参数。
  • response.delete_cookie(key, path='/', domain=None):用于删除一个 cookie。
  • response.autocorrect_location_header(url):自动纠正 Location 头字段中的相对 URL。
  • response.get_data():获取响应体的内容。如果内容被编码,它将返回编码后的版本。
  • response.get_json():如果响应体是 JSON 格式的,这个方法可以解析并返回一个 Python 对象。

response 对象代表了客户端接收到的 HTTP 响应。这个对象通常是通过 Flask 的 make_response 函数或者 jsonify 函数创建的。

from flask import Flask, make_response, jsonify

app = Flask(__name__)

@app.route('/')
def index():
    # 使用 make_response 创建响应对象
    response = make_response('<h1>Hello World</h1>', 200)
    response.headers['Content-Type'] = 'text/html'
    response.headers['X-Custom-Header'] = 'Custom Value'
    return response

@app.route('/json')
def json_response():
    # 使用 jsonify 创建 JSON 响应
    data = {'key': 'value'}
    response = jsonify(data)
    response.status_code = 200
    response.headers['X-Custom-Header'] = 'Custom Value'
    return response

if __name__ == '__main__':
    app.run()

FastAPI

FastAPI:https://fastapi.tiangolo.com/zh/ 

1.获取请求参数

获取 GET 参数:

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_query_item(q: str = Query(...)):
    return {"q": q}

Form 用于从 application/x-www-form-urlencoded 或 multipart/form-data 编码的请求体中获取数据,通常用于处理表单提交的数据。以下是 Form 支持的参数:

  • default: 设置参数的默认值。
  • min_length: 字符串的最小长度。
  • max_length: 字符串的最大长度。
  • regex: 字符串必须匹配的正则表达式。
  • required: 指定字段是否为必填项,默认为 True。

获取POST参数:

from fastapi import FastAPI, Form

app = FastAPI()

@app.post("/items/")
async def create_item(name: str = Form(...), price: float = Form(...)):
    return {"name": name, "price": price}

Query 用于从 URL 的查询字符串中获取数据。它支持以下参数:

  • default: 设置参数的默认值。
  • alias: 为参数设置一个别名,这在 URL 中使用的名称与函数参数名称不一致时非常有用。
  • title: 为参数设置一个标题,这通常用于 API 文档。
  • description: 为参数提供一个描述,这在 API 文档中显示,有助于说明参数的用途。
  • gt (greater than): 参数值必须大于指定的值。
  • lt (less than): 参数值必须小于指定的值。
  • ge (greater than or equal to): 参数值必须大于或等于指定的值。
  • le (less than or equal to): 参数值必须小于或等于指定的值。
  • min_length: 参数的最小长度(对于字符串)。
  • max_length: 参数的最大长度(对于字符串)。
  • regex: 参数值必须匹配指定的正则表达式。
  • example: 为参数提供一个示例值,这在 API 文档中显示。

获取JSON参数:

from fastapi import FastAPI

app = FastAPI()

@app.post("/items/")
async def create_item(item: dict):
    return {"item": item}

2.Request对象

Request 对象代表了进入应用的 HTTP 请求。

from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/items/")
async def read_items(request: Request):
    query_param = request.query_params("query")  # 获取查询参数
    headers = request.headers  # 获取请求头
    body = await request.json()  # 获取 JSON 请求体
    return {"query_param": query_param, "headers": dict(headers), "body": body}

3.Response 对象

Response 对象用于构建和返回 HTTP 响应。

from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/items/")
async def read_items(response: Response):
    content = {"item": "some item"}
    response.headers["X-Custom-Header"] = "Value"  # 设置响应头
    response.status_code = 200  # 设置状态码
    return response  # 返回 Response 对象

4.校验JSON参数

在 FastAPI 中,当你在路径操作函数中声明一个参数,并将其类型指定为 Pydantic 模型时,FastAPI 会自动将请求体解析为 JSON 并进行验证。

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
    return {"name": item.name, "description": item.description}

卷积神经网络 

卷积神经网络(Convolutional Neural Networks,CNN)是人工智能领域中一种重要的深度学习模型,被广泛应用于图像识别、目标检测、自然语言处理等领域。

1.大模型平台

Python项目

收集一些很厉害的Python仓库:

大模型:

实用库:

Rembg

Rembg 是一个基于 Python 的背景去除工具,它使用深度学习技术来从图像中去除背景。

Pytorch:https://pytorch.org/get-started/locally/

开源地址:https://github.com/danielgatis/rembg

详见Github仓库的说明:https://github.com/danielgatis/rembg

1.基础知识

相关名词介绍:

  • U2-Net是由Xuebin Qin等人开发的一种用于显著目标检测(Salient Object Detection, SOD)的深度学习模型。
  • ONNXRuntime是由微软推出,用于优化和加速机器学习推理和训练,适用于ONNX模型,是一个跨平台推理和训练机器学习加速器(ONNX Runtime is a cross-platform inference and training machine-learning accelerator)
  • Rembg和U2-Net之间的关系是工具与核心算法的关系,Rembg利用U2-Net作为其图像分割的引擎。

开源地址:

2.关于训练模型

  • 数据收集:人工或自动化工具收集数据,这可能包括从数据库、文件、网络或其他数据源获取数据。
  • 数据清洗:人工检查数据集,识别并处理缺失值、异常值和错误数据。
  • 特征选择:人工或使用自动化算法选择对模型预测有用的特征。
  • 数据标注:对于监督学习,需要人工标注数据,例如在图像识别中标记图像中的物体,在文本分类中为文本分配类别标签。
  • 数据分割:人工或使用自动化方法将数据集分割为训练集、验证集和测试集。
  • 模型选择:根据问题的性质和数据的特点,人工选择或设计一个合适的模型。
  • 模型配置:人工设置模型参数,如神经网络的层数和节点数,选择损失函数和优化器。
  • 训练过程:通常由自动化脚本执行,但人工可能需要监控训练过程,调整参数以优化模型性能。
  • 模型评估:使用验证集或测试集评估模型,人工分析评估结果,确定模型是否满足要求。
  • 模型调优:根据评估结果,人工调整模型结构或参数,进行超参数优化。
  • 模型验证:人工验证模型在实际应用中的性能,确保模型的泛化能力。
  • 模型部署:将训练好的模型部署到生产环境,可能需要人工配置和监控。

3.问题记录

importing onnxruntime_pybind11_state: 找不到指定的模块

安装VC_redist:https://aka.ms/vs/16/release/VC_redist.x64.exe

FunASR

FunASR是一个基础语音识别工具包,提供多种功能,包括语音识别(ASR)、语音端点检测(VAD)、标点恢复、语言模型、说话人验证、说话人分离和多人对话语音识别等。

Github:https://github.com/modelscope/FunASR/blob/main/README_zh.md#%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B

1.安装

服务端部署文档:https://github.com/modelscope/FunASR/blob/main/runtime/readme_cn.md

# 安装
pip3 install torch torchvision torchaudio

# 安装
pip3 install -U funasr

Segment Anything

Github:https://github.com/facebookresearch/segment-anything

AI大模型

记录使用AI大模型产品的过程中,遇到的一些常见问题:

1.16k、32k这些参数的区别?

对于那本长篇小说,128k模型几乎可以记住整本书的内容。所以,无论你问到小说的哪个部分,它都能给出非常详细和准确的回答。

简单来说,这些数字(16k、32k、128k)代表了AI模型的“记忆力”。记忆力越强,模型在处理长文本和复杂对话时就越出色,能够生成更加丰富和连贯的回答,以16k为例:

  • 输入:如果你给这个模型发送一段文本,它最多能记住大约16,000个单词的信息。
  • 输出:当它回复你时,它的回答将基于这16,000个单词的信息。如果你们的对话非常长,超过了这个字数,它可能就会“忘记”一些早期的信息。
  • 例子:假设你们正在讨论一本长篇小说,16k模型可能只能记住小说的一小部分内容,所以在回答关于小说结尾的问题时,它可能记不住开头的细节。