‹ 返回笔记 Esc·

Python 问题与修复

全局安装 python 报错 系统检查到当前 Python 解释器属于 系统管理环境,即由操作系统包管理器(如 apt)负责管理。这时候直接用 pip 安装包会破坏系统依赖,因此 pip 阻止该行为并…

全局安装 python 报错

1  ~ pip install modelscope
2error: externally-managed-environment
3
4× This environment is externally managed
5╰─> To install Python packages system-wide, try apt install
6    python3-xyz, where xyz is the package you are trying to
7    install.
8
9    If you wish to install a non-Debian-packaged Python package,
10    create a virtual environment using python3 -m venv path/to/venv.
11    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
12    sure you have python3-full installed.
13
14    If you wish to install a non-Debian packaged Python application,
15    it may be easiest to use pipx install xyz, which will manage a
16    virtual environment for you. Make sure you have pipx installed.
17
18    See /usr/share/doc/python3.12/README.venv for more information.
19
20note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
21hint: See PEP 668 for the detailed specification.

系统检查到当前 Python 解释器属于 系统管理环境,即由操作系统包管理器(如 apt)负责管理。这时候直接用 pip 安装包会破坏系统依赖,因此 pip 阻止该行为并提示:

  • 想在系统层面安装,请用系统软件包管理器(如 apt install python3-xyz)。
  • 推荐创建 虚拟环境 使用 pip 安装。
  • 也可以用 pipx 安装命令行工具或强制使用 --break-system-packages(但有风险)。

此行为基于 Python PEP 668 标准设计。

如果您非要在系统环境安装,可以加上:

1pip install modelscope --break-system-packages

或者全局设置强制允许(风险高):

1python3 -m pip config set global.break-system-packages true

注意:此方案可能导致操作系统工具(如 apt、gnome-terminal、systemd 等)异常,可能破坏系统稳定性。仅在特殊场景下使用。


检测项目虚拟环境位置

1which pip
2which python

正确路径是path/.venv/bin/pippath/.venv/bin/python


全局范围代码执行逻辑

如果某个 Python 文件(例如 module.py)中定义了一些全局代码(即在函数或类之外的代码),这些代码只会在该文件被直接执行时运行。也就是说,只有当你通过入口代码(例如 main.py)显式导入并调用 module.py 文件中的方法或执行某些代码时,module.py 中的全局范围代码才会被执行。

1print("This is global code in module.py")  # 这行代码会被执行
2
3def some_function():
4    print("This is a function.")
1import module  # 这只会导入 module.py,但不会执行 module.py 中的全局代码
2
3# 如果你想要执行 module.py 中的代码,你需要显式调用一些函数
4module.some_function()

此时,执行 python main.py 时,不会输出 module.py 中的全局代码,因为全局代码没有被执行,只有显式调用的函数才会被执行:

全局代码(位于函数或类之外的代码)在 Python 中 只有在文件被直接执行时才会执行,而如果该文件仅被导入,代码不会执行。


JSON 格式字符串乱码

1import json
2info = {"content": "错误"}
3dumps = json.dumps(info, ensure_ascii=False)
4print(dumps) # 输出 {"content": "错误"}

其中ensure_ascii=False参数告诉json.dumps()方法使用原生 Unicode 字符,而不是通过 ASCII 转义字符来表示非英文字符。

因此,在上述示例代码中输出时就会直接显示中文字符,而不是出现类似于\u9519\u8bef的转义字符了。


raise_for_status() 方法的作用

1import requests
2from requests.exceptions import HTTPError
3
4try:
5    res = requests.get('https://api.github.com/invalid-endpoint')
6    res.raise_for_status()
7except HTTPError as e:
8    print("HTTP error occurred:", e)
9except Exception as e:
10    print("Other error occurred:", e)
11else:
12    print("Request succeeded.")

raise_for_status() 属于 Response 对象的方法,用于检查 HTTP 响应的状态码:若状态码表示请求失败(即 400–599 的状态码),则抛出 HTTPError 异常;若为成功状态码(200–299),则不会抛出异常


mysql-connector 结果用字段名称获取

1db = connect(host="127.0.0.1", port=3306, user="root", password="123456", database="dt_crm")
2cursor = db.cursor(dictionary=True)
3query_sql = ("SELECT college_name, college_code, major_name, subject_one, subject_two, subject_three, subject_four, "
4             "retest_subject, `year`, admit_num  FROM choose_school WHERE college_name = '安徽大学' "
5             "AND major_name = '人工智能' AND `year` = 2025 LIMIT 1")
6cursor.execute(query_sql)
7one = cursor.fetchone()
8college_name = one['college_name']
9print(college_name)

字典游标:在连接数据库时使用 cursor(dictionary=True) 来创建字典游标。

查询结果:每一行的结果都将是一个字典,字段名作为字典的键,字段值作为字典的值。

字段访问:你可以直接通过字段名(例如 one[‘college_name’])来获取字段的值。可以不需要通过索引 one[0] 获取字段值。


在网络受限的环境中运行

  1. 准备依赖,确保项目依赖都列在 requirements.txt 文件中,可以使用 pip freezepipreqs 来生成 requirements.txt 文件
1pip freeze > requirements.txt
  1. 下载依赖包(.whl 尾缀文件),使用 pip download 命令在有网络的环境中下载项目所需的所有包。可以使用 -d 参数指定下载目录
1pip download -r requirements.txt -d ./packages
  1. 打包压缩并迁移项目,将你的项目文件(包括代码、requirements.txt、以及 packages 目录)打包,再使用压缩工具(如 ziptar)来创建一个压缩包
1zip -r my_project.zip my_project/ requirements.txt packages/
  1. 转移到受限环境中解压
1unzip my_project.zip
  1. 安装依赖包
1pip install --no-index --find-links=./packages -r requirements.txt
  • --no-index:表示不从网络获取包
  • --find-links:指定本地包目录

控制台输出字体颜色

  1. ANSI 转义序列
1print("\033[31m这是红色文字\033[0m")
2print("\033[32m这是绿色文字\033[0m")
3print("\033[33m这是黄色文字\033[0m")
4print("\033[34m这是蓝色文字\033[0m")
5print("\033[1;35m这是紫色加粗文字\033[0m")

**style**

  • 0:默认样式
  • 1:高亮/加粗
  • 4:下划线
  • 7:反色
颜色 前景色代码 背景色代码
黑色 30 40
红色 31 41
绿色 32 42
黄色 33 43
蓝色 34 44
紫色 35 45
青色 36 46
白色 37 47
  1. 使用 colorama 库
1pip install colorama
2
3from colorama import Fore, Back, Style, init
4
5# 初始化(在 Windows 中需要调用 init())
6init()
7
8# 前景色
9print(Fore.RED + "这是红色文字")
10print(Fore.GREEN + "这是绿色文字")
11
12# 背景色
13print(Back.YELLOW + "这是带黄色背景的文字")
14print(Back.BLUE + Fore.WHITE + "这是带蓝色背景和白色文字的文字")
15
16# 样式
17print(Style.BRIGHT + "这是加粗文字")
18print(Style.RESET_ALL + "重置样式,回到普通文字")
19
20# 日常使用
21log.info(Fore.BLUE + f"Question: {question}" + Style.RESET_ALL)

路径拼接

BASE_DIR通常是项目的根目录的路径,它是一个字符串。

  • LOG_PATH = BASE_DIR / "logs" 这行代码使用了 Python 3.4 及以后版本中引入的路径操作符 /。它用于连接两个路径组件,创建一个新的路径对象。在这种情况下,BASE_DIR应该是一个pathlib.Path 对象,而不是一个简单的字符串。使用这种方法,Python 会自动处理路径分隔符,无论是Windows上的\ 还是Unix/Linux上的/
  • LOG_PATH = BASE_DIR + "logs" 这一行代码使用了字符串的+操作符来连接BASE_DIR 和字符串"logs"。这里BASE_DIR 必须是一个字符串。然而,这种方法不会自动处理路径分隔符,因此可能会在不同的操作系统上产生不同的结果。例如,在 Windows 上,可能需要使用os.path.join(BASE_DIR, "logs")来确保路径分隔符是正确的。

总结:

  • 第一种方法(使用/操作符)更加现代,且能自动处理路径分隔符。它要求 BASE_DIR 是一个 pathlib.Path 对象。
  • 第二种方法(使用+操作符)更简单,但可能不会正确处理路径分隔符,尤其是在不同的操作系统上。它要求 BASE_DIR 是一个字符串。

连锁赋值

1admit_volunteer_number = admit_adjusted_number = admit_volunteer_max_score = "-"
  • 这个语法通过连锁赋值(chained assignment)实现了将同一个值 “-” 赋给多个变量。
  • 右侧的 “-” 首先被赋值给 admit_volunteer_max_score,然后再依次赋值给其他两个变量 admit_adjusted_number 和 admit_volunteer_number。

解构变量

1def sql_query(college_name: str, major_name: str):
2    admit_adjust_max_score = 100
3    admit_adjust_min_score = 20
4    admit_target_score = 60
5    return admit_adjust_max_score, admit_adjust_min_score, admit_target_score
6
7query = sql_query("南京大学", "软件工程")
8admit_adjust_max_score, admit_adjust_min_score, admit_target_score = query

当你调用 sql_query 时,它返回一个元组,你可以将元组中的各个值解构到多个变量中。


\n 换行符标记不转义

保留字符串中的 \n 而不是将其转换为换行,可以使用原始字符串(raw string)。

在Python中,原始字符串通过在字符串前加上 rR 来创建。这样,字符串中的反斜杠 \ 就不会被当作转义字符处理。

1for chunk in streams:
2    answer += chunk
3    print(repr(chunk))  # 使用repr来打印chunk,这样可以显示实际的字符串内容,包括\n

Typing 类型

这里的Optional[dict[str, Any]] 表示的是一个变量,它可以是一个字典,其键是字符串类型,值可以是任何类型(Any),或者这个变量的值可以是 NoneAnytyping 模块中的一个特殊类型,用于表示“任何类型”。当我们知道一个变量的类型可能会变化,或者我们不想限制它的类型时,可以使用 Any

1from typing import Optional, Dict, Any
2# 定义一个变量,它可以是一个字典,也可以是None
3my_var: Optional[Dict[str, Any]] = None
4# 也可以是一个具体的字典
5my_var = {
6    "name": "Alice",
7    "age": 30,
8    "is_student": False
9}

推导式

  1. 列表推导式
1names = ['Bob','Tom','alice','Jerry','Wendy','Smith']
2new_names = [name.upper() for name in names if len(name)>3]
3print(new_names)
4# ['ALICE', 'JERRY', 'WENDY', 'SMITH']
  1. 字典推导式
1listdemo = ['Google', 'Runoob', 'Taobao']
2newdict = {key:len(key) for key in listdemo}
3print(newdict)
4# {'Google': 6, 'Runoob': 6, 'Taobao': 6}
  1. 集合推导式
1a = {x for x in 'abracadabra' if x not in 'abc'}
2print(a)
3# {'d', 'r'}
  1. 元组推导式
1a = (x for x in range(1,10))
2print(a)
3<generator object <genexpr> at 0x7faf6ee20a50>  # 返回的是生成器对象
4print(tuple(a))       # 使用 tuple() 函数,可以直接将生成器对象转换成元组
5# (1, 2, 3, 4, 5, 6, 7, 8, 9)

yield 生成器

yield 关键字用于创建生成器(generator)。生成器是一种特殊的迭代器,它允许你逐个产生值,而不是一次性产生所有值。yield 关键字必须用在函数(def 语句定义的函数)或者协程(使用 async def 定义的异步函数)内部。

当你调用一个包含 yield 的函数时,Python 会返回一个生成器对象。你可以使用 next() 函数或者在循环中迭代这个生成器,每次迭代都会执行到下一个 yield 表达式,并返回它的值。

1def my_generator():
2    yield 1
3    yield 2
4    yield 3
5
6# 使用生成器
7gen = my_generator()
8print(next(gen))  # 输出: 1
9print(next(gen))  # 输出: 2
10print(next(gen))  # 输出: 3

在这个例子中,my_generator 函数是一个生成器,它逐个产生值 1、2 和 3。 yield 不能独立使用,也不能用在类定义、模块级别或者表达式中。它必须位于函数或协程的内部,以产生值。如果尝试在其他地方使用 yield,Python 解释器会抛出语法错误。


右箭头返回类型 ->

-> 右边指的是这个函数的返回类型,用于校验出参结果

1def embed_documents() -> List[int]:
2    return [111, 222]

类型除了有Typing里的List、Any、Optional,还有内建基本类型list、str、int Optional[int]表示一个变量可以是int类型或者None。 Any表示一个变量可以是任何类型。

在Python 3.10及以后的版本中,typing模块引入了一个新的|运算符,用于表示类型联合(Type Union),这使得你可以用更简洁的语法来表示一个变量可以是多种类型之一。这使得Optional类型可以被更简洁地表达。例如:

1def greet(name: str | None = None) -> str:
2    pass

在这个例子中,name参数可以是str类型或者None,这与使用Optional[str]是等价的。这种新语法提供了更简洁和直观的方式来表达类型可选性。


位置参数与关键字参数

1def my_function(*args, **kwargs):
2print("位置参数:", args)
3print("关键字参数:", kwargs)
4# 调用 my_function 函数
5my_function(1, 2, "哈哈", name="Alice", age=30, info={"1", "2"})

其中1、2、"哈哈"*args, name="Alice", age=30, info={"1", "2"}**kwargs

*args:这被称为“可变位置参数”(Arbitrary Argument List)。它允许你向函数传递任意数量的位置参数,这些参数将被收集到一个名为args的元组(tuple)中。使用星号(*)来表示。

**kwargs:这被称为“可变关键字参数”(Arbitrary Keyword Argument Dictionary)。它允许你向函数传递任意数量的关键字参数,这些参数将被收集到一个名为kwargs的字典(dict)中。使用两个星号(**)来表示。


使用装饰器函数缺少文档字符串报错

1ValueError: Function must have a docstring if description not provided.
1@tool
2def search(query: str):
3    """Call to surf the web."""
4    if "sf" in query.lower() or "san francisco" in query.lower():
5        return "It's 60 degrees and foggy."
6    return "It's 90 degrees and sunny."

要解决这个问题,可以为 search函数添加一个简短的文档字符串,描述该函数的功能。

通过添加 “”“Call to surf the web.”“” 这一行,解释了 search 函数的作用,这样 @tool 装饰器就能够获取描述并成功运行。


跨不同操作系统的路径分隔符

1import os
2from pathlib import Path
3
4# os.path.join 示例
5upload_path_os = os.path.join(os.path.expanduser("~"), "uploads")
6print("os.path.join:", upload_path_os)
7
8# pathlib 示例
9upload_path_pathlib = Path.home() / "uploads"
10print("pathlib:", upload_path_pathlib)

循环遍历从 1 开始

1data_list = sql_query("XXX")
2for index, item in enumerate(data_list, start=1):  # 从1开始编号
3    print(f"第 {index} 个数据: {item}")

从字典或JSON获取值的方式

1val = row.get('id')
2val = row.get('id', default_value) # default_value 是可选参数,用于指定键不存在时的返回值。
3
4val = row['id']

row.get('id')

  • 更安全,推荐在不确定键是否存在时使用。
  • 如果键 ‘id’ 不存在,get() 方法会返回一个默认值(默认是 None),不会抛出异常。

row['id']

  • 如果键 ‘id’ 不存在,会抛出 KeyError 异常。
  • 适合在确定键 ‘id’ 一定存在的情况下使用。

f-string 和 字符串拼接 (+)

1f"mysql+aiomysql://{settings.database_url}"
2
3"mysql+aiomysql://" + settings.database_url

f-string:

  • f-string 在 Python 3.6 及以上版本中是推荐的格式化字符串方式。
  • 在拼接多个变量或复杂表达式时,性能更优,因为 f-string 是在编译阶段生成的高效字节码。

字符串拼接 (+):

  • 每次使用 + 都会创建一个新的字符串对象,增加了内存分配和性能开销。对于多个拼接操作,性能可能会下降。

列表生成式写法

1doc_list = [
2    Document(
3        page_content=fake.sentence(),
4        metadata={
5            "db_id": random.randint(1, 100),
6            "timestamp": 1703001600,
7            "tag": ["通信", "通信技术"]
8        }
9    )
10    for _ in range(100)
11]

列表生成式(List Comprehension)的写法,用来生成一个包含 100 个 Document 对象的列表 doc_list。

在这段代码中,循环的目的仅仅是重复生成 100 个 Document 对象,而不关心 range(100) 中的具体值。因此,用 _ 更加符合惯例,表示「循环变量不被使用」。

  1. for _ in range(100)

_ 是一种惯例,表示循环变量的值不需要被使用。

这种写法明确表达了循环体中不会用到循环变量(即每次循环仅为了执行操作,而不关心具体的值)。

在代码中更加语义化,适合用于生成列表或重复性任务。

  1. for item in range(100)

item 是一个有效的变量名,表示当前循环中的具体值。

当你需要在循环中用到该值时,使用 item 是更合适的。


gobal 关键字使用

1scheduler = BackgroundScheduler()
2
3def scheduler_startup():
4    global scheduler  # 允许修改全局变量
5    if scheduler.running:
6        return result.error(msg="定时任务已在运行")
7    else:
8        scheduler = BackgroundScheduler()

开终端代理报错 Using SOCKS proxy

1ImportError: Using SOCKS proxy, but the 'socksio' package is not installed. Make sure to install httpx using pip install httpx[socks].

关闭掉 .zshrc 中的 export ALL_PROXY=socks5://127.0.0.1:7897 代理