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/pip与 path/.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] 获取字段值。
在网络受限的环境中运行
- 准备依赖,确保项目依赖都列在
requirements.txt文件中,可以使用pip freeze或pipreqs来生成requirements.txt文件
1pip freeze > requirements.txt
- 下载依赖包(.whl 尾缀文件),使用
pip download命令在有网络的环境中下载项目所需的所有包。可以使用-d参数指定下载目录
1pip download -r requirements.txt -d ./packages
- 打包压缩并迁移项目,将你的项目文件(包括代码、
requirements.txt、以及packages目录)打包,再使用压缩工具(如zip或tar)来创建一个压缩包
1zip -r my_project.zip my_project/ requirements.txt packages/
- 转移到受限环境中解压
1unzip my_project.zip
- 安装依赖包
1pip install --no-index --find-links=./packages -r requirements.txt
--no-index:表示不从网络获取包--find-links:指定本地包目录
控制台输出字体颜色
- 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 |
- 使用 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中,原始字符串通过在字符串前加上 r 或 R 来创建。这样,字符串中的反斜杠 \ 就不会被当作转义字符处理。
1for chunk in streams:
2 answer += chunk
3 print(repr(chunk)) # 使用repr来打印chunk,这样可以显示实际的字符串内容,包括\n
Typing 类型
这里的Optional[dict[str, Any]] 表示的是一个变量,它可以是一个字典,其键是字符串类型,值可以是任何类型(Any),或者这个变量的值可以是 None。
Any 是 typing 模块中的一个特殊类型,用于表示“任何类型”。当我们知道一个变量的类型可能会变化,或者我们不想限制它的类型时,可以使用 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}
推导式
- 列表推导式
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']
- 字典推导式
1listdemo = ['Google', 'Runoob', 'Taobao']
2newdict = {key:len(key) for key in listdemo}
3print(newdict)
4# {'Google': 6, 'Runoob': 6, 'Taobao': 6}
- 集合推导式
1a = {x for x in 'abracadabra' if x not in 'abc'}
2print(a)
3# {'d', 'r'}
- 元组推导式
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) 中的具体值。因此,用 _ 更加符合惯例,表示「循环变量不被使用」。
for _ in range(100)
_ 是一种惯例,表示循环变量的值不需要被使用。
这种写法明确表达了循环体中不会用到循环变量(即每次循环仅为了执行操作,而不关心具体的值)。
在代码中更加语义化,适合用于生成列表或重复性任务。
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 代理