Python单例模式实现详解:从模块缓存到元类,避开线程安全与序列化坑
单例模式应该是Python里讨论度最高、但写法争议也最大的设计模式之一。我在不少项目代码里见过五花八门的实现有人把__new__写得花里胡哨有人用装饰器把类包成函数还有人硬靠classmethod凑出一个所谓的单例。说起来单例本身的概念很简单——保证一个类在程序整个生命周期里只有一个实例并提供一个全局访问点。但放到Python这个语言里因为模块缓存机制、动态类型、元类这些语言特性实现方式比Java、C要多得多坑也藏得深。这篇文章我不打算复述教科书而是从“为什么Python的单例和别的语言不一样”讲起把手写一遍四种主流实现、线程安全、序列化、测试重置这些实际项目绕不开的点一次性讲透。内容适合刚接触Python、想搞懂单例到底该怎么写的新手也适合写了几年Python但没认真抠过这些细节的老手。1. 为什么Python的单例模式和别的语言差别这么大1.1 单例模式的本质与真实适用场景单例模式本质上解决两个约束第一个是“唯一性”就是一个类的实例在进程内只存在一份第二个是“可达性”就是代码任何地方都能拿到这份实例不用层层传递依赖。这两个约束听起来简单实现时却会碰到很多岔路。最常见的应用对象是数据库连接池、日志处理器、配置管理、缓存客户端它们的共同点是创建成本高比如连接数据库需要握手和鉴权同时全局状态一致很重要比如配置对象不能同时存在两份互相矛盾的值。但这里要先泼一盆冷水不是所有“看起来只会用一次”的对象都适合做成单例。如果一个对象只是恰好被一个模块内部用到那根本不需要全局访问点直接在局部创建就行。滥用单例的典型症状是代码里到处是Config.getInstance()线程之间共享了不该共享的可变状态遇到问题时很难定位是谁改了配置。所以在决定用单例之前先问自己三个问题这个对象真的需要全局唯一吗全局共享会不会引入状态同步问题有没有比单例更自然的依赖传递方式这三个问题在Python里尤其值得问因为Python的模块机制本身就能承担一部分单例职责很多时候根本不需要额外写单例类。1.2 Python模块缓存机制天然的单例容器Python和其他静态语言最大的不同在于模块导入时会被缓存到sys.modules这个字典里。一个模块只要import过一次第二次再import的时候Python会直接返回缓存里的模块对象不会重新执行模块顶层的代码。这个机制意味着模块里的全局对象天然是进程内唯一的。所以Python里最朴素的单例甚至不需要写任何“单例技巧”只需要在模块顶层创建对象并导出就行。# db_pool.py import threading class DatabasePool: def __init__(self, dsn): self.dsn dsn self._connections [] self._lock threading.Lock() def acquire(self): with self._lock: return self._connections.pop() _pool DatabasePool(mysql://localhost:3306/app) def get_pool(): return _pool我自己的项目里大量使用这种写法。它没有动用任何设计模式技巧但确实满足了唯一性和可达性。原理也很简单sys.modules缓存是解释器层面的保证任何地方import db_pool拿到的模块对象都一样那_pool自然也就只有一份。可以这样理解Python从语言设计上就内置了一个轻量级单例容器只是一部分教材忽略了这一层导致很多人一提到单例就下意识去写__new__或元类。模块级单例唯一的瑕疵是它不支持延迟创建——模块被import时对象就创建了。如果创建对象本身开销很大或者需要依赖运行时参数才能初始化就需要考虑下面这些更灵活的实现。2. 四种主流实现方式逐个拆解2.1 模块级单例最Pythonic的写法模块级单例的代码上面已经给了例子关键点就两个第一实例在模块顶层创建第二对外提供访问函数或直接导出实例变量。推荐用访问函数而不是直接暴露变量这样后续如果想加懒加载、重置逻辑或者参数校验可以不动调用方的代码。# config_manager.py import os class ConfigManager: def __init__(self): self.env os.getenv(APP_ENV, production) self.debug os.getenv(DEBUG, false).lower() true _config None def get_config(): global _config if _config is None: _config ConfigManager() return _config上面这个写法其实比“模块顶层直接实例化”更稳健它把创建动作延后到第一次调用get_config()时。这在面对环境变量初始化时会方便不少因为你可以控制初始化的时机规避“import时环境还没准备好”的问题。如果项目里没有这种需求直接模块顶层实例化也完全没问题。这种方案的优点非常明显代码量最少、心智负担最低、调试最方便直接看模块变量就行。缺点也很直接它不能阻止别人直接ConfigManager()新建实例。如果有人不小心import config_manager后直接实例化单例约束就破了。所以模块级单例适合团队内部约定清晰的场景如果是要写一个库给别人用最好还是用下面几种能强制约束的方式。2.2 基于__new__的实现教科书最常见的写法用__new__拦截实例创建是网上一搜一大把的写法。核心思路是重写__new__方法在分配内存前检查类属性_instance是否已存在。class Singleton: _instance None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance super().__new__(cls) return cls._instance def __init__(self, name): # 注意这个方法每次创建调用时都会执行 self.name name这个写法看起来干净但有两个很隐蔽的坑。第一个坑是__init__会被重复执行。__new__虽然只创建一次内存但每次写Singleton(a)都会走到__init__也就是说单例的实例会被反复初始化。如果__init__里有重活比如加载大配置、建立连接就会被浪费掉。解决方案是把初始化逻辑放到__new__里用一个_initialized标记控制只执行一次class Singleton: _instance None _initialized False def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance super().__new__(cls) if not cls._initialized: cls._initialized True cls._instance._init_once(*args, **kwargs) return cls._instance def _init_once(self, name): self.name name第二个坑是子类问题。如果你继承了Singleton类cls._instance会被子类共享导致父类和子类返回同一个实例而如果你在__new__里用hasattr而不是is None判断又会变成每个子类都有自己的独立实例。这到底是好事还是坏事取决于业务需求但至少要知道行为是这样的否则容易踩到“两个类拿了同一个实例”的诡异问题。2.3 装饰器实现代码复用性最高的方案装饰器方案适合“这个类本来不想为单例做任何改动”的场景。把单例逻辑抽到装饰器里原类保持干净这是我很喜欢的一种结构。def singleton(cls): instances {} def get_instance(*args, **kwargs): if cls not in instances: instances[cls] cls(*args, **kwargs) return instances[cls] return get_instance singleton class Config: def __init__(self): self.env production注意这个实现有一个特性instances字典是以类为key的所以同一个装饰器可以装饰多个类每个类各自拥有自己的单例实例。上面的写法里cls(*args, **kwargs)只会执行一次之后无论传什么参数返回的都是第一次创建的实例参数会被静默忽略——这在某些场景下是好事保证不会重复创建但如果你期望“传入不同参数时返回不同配置对象”那就要小心了。装饰器方案的一个麻烦点是singleton返回的是一个普通函数所以Config这个“类”不再是一个真正的类isinstance(obj, Config)这类操作会失效。如果代码里依赖类型判断会遇到问题。改进办法是让装饰器返回一个类对象def singleton(cls): class SingletonWrapper(cls): _instance None def __new__(cls_new, *args, **kwargs): if cls_new._instance is None: cls_new._instance super().__new__(cls_new) return cls_new._instance return SingletonWrapper这么写会让isinstance正常工作但引入了继承层级可能改变类之间的关系。所以我的建议是如果只是自己项目里用、不对外暴露API函数版装饰器足够如果要写库给别人优先考虑元类方案。2.4 元类方案框架级实现的首选元类(base metaclass)方案是目前工程上最被推崇的实现也是很多框架内部采用的方式。原理是利用type.__call__的流程——一个类被调用创建实例时实际上走的是其元类的__call__方法。所以只要在元类的__call__里做单例判断即可。import threading class SingletonMeta(type): _instances {} _lock threading.Lock() def __call__(cls, *args, **kwargs): if cls not in cls._instances: with cls._lock: if cls not in cls._instances: cls._instances[cls] super().__call__(*args, **kwargs) return cls._instances[cls] class Config(metaclassSingletonMeta): def __init__(self): self.env production元类方案的优点非常突出。它没有改变类的本质Config依旧是一个类isinstance等类型操作全部正常它以cls为key存储实例天然支持子类各自拥有独立的单例它不需要侵入业务类的__new__业务代码保持干净。这段代码里我直接加了锁和双重检查这在多线程环境下是必须的。很多人写元类单例时会省略锁然后在并发请求场景下偶发创建出两个不同的连接池实例问题定位起来极其痛苦。cls._instances字典在类层面共享不加锁时两个线程可能同时发现“实例不存在”然后各自创建一份单例就不再是单例了。上面代码用了双重检查锁定先快速检查一次避免每次都拿锁再在锁内重新检查一次防止并发创建。这样兼顾了性能和正确性是推荐的写法。3. 线程安全与懒加载这些关键细节3.1 懒加载与急加载怎么选“懒加载”指的是实例在第一次被使用时才创建“急加载”指的是程序启动或import时立即创建。两种方式没有绝对的好坏关键看场景。数据库连接池和缓存客户端适合懒加载因为连接池依赖的配置可能要等到运行时才知道过早创建既拿不到正确配置还会白白占用资源。日志处理器则更适合急加载它需要尽早就绪确保任何代码晕出的日志都能被记录到。Python模块级单例天然是急加载的因为模块import时就执行了顶层代码。上一节我给的get_config()版本则实现了懒加载。元类和__new__实现默认也是懒加载因为类第一次被调用时才创建实例。如果在这些方案里也想实现急加载可以在模块顶层显式调用一次构造函数比如# 在模块顶层主动创建实例实现急加载 _config_instance Config()这个技巧在那些希望“导入即初始化”的框架集成场景里很有用。3.2 线程安全实现与完整示例前面提到的元类代码里已经包含了线程安全处理。除了加锁还有一个常见隐患是如果你的单例类在__init__里做了耗时操作多个线程虽然只会执行一次__init__但等待锁的其他线程仍然可能拿到“只创建到一半”的实例。严格来说super().__call__()返回的实例一定是完整的因为__init__执行完毕才会返回锁保证了这个过程不会被打断。所以双重检查锁在这个场景下是安全的。下面是一个完整的线程安全参数化单例示例很多实际项目可以直接套用。这里的参数化是指第一次调用时传入的参数会被保存后续调用即便传入不同参数也只会返回首次创建的那个实例。import threading import time class SingletonMeta(type): _instances {} _lock threading.Lock() def __call__(cls, *args, **kwargs): if cls not in cls._instances: with cls._lock: if cls not in cls._instances: instance super().__call__(*args, **kwargs) cls._instances[cls] instance return cls._instances[cls] class DatabasePool(metaclassSingletonMeta): def __init__(self, host, port): self.host host self.port port self.connections [] print(f连接 {host}:{port}) time.sleep(1) # 模拟耗时初始化在并发测试里开10个线程同时调用DatabasePool(localhost, 3306)最终只会打印一次连接信息。如果不加锁你可能会看到多次连接打印这就是单例被破坏的直接证据。需要提醒的是这里的线程安全仅限于创建过程。如果单例对象的实例方法本身有可变状态操作比如更新配置项仍然需要你自行处理同步单例模式并不负责这一步。3.3 多线程应用中的协调问题有一种比“实例唯一”更严格的要求是“跨线程协调”。比如有些单例内部持有一个队列多个线程往里push、pop。这种情况下即使单例创建过程是线程安全的队列操作也得加锁。我的习惯是所有会发生读写的单例对象内部状态一律用锁保护不要依赖外部调用方来保证线程安全。这样设计出来的单例才是真正可靠的。还有一类容易被忽视的场景是异步编程。在协程async/await环境里多个协程可以交错执行单例内部的共享状态如果被一个协程修改后还没恢复另一个协程就开始读取就会出事。这个时候需要额外设计协程间的协调机制比如用asyncio.Lock替代普通threading.Lock或者干脆避免在单例里保存请求级别的上下文。单独为一个单例引入异步锁可能有些重但如果你写的是一个被很多协程共享的连接池或缓存这个投入是值得的。4. 进阶坑位序列化、子类化与测试重置4.1 序列化会破坏单例序列化pickle是单例的一个藏得比较深的敌人。原因在于pickle在反序列化时通常不会调用类的__init__和__new__而是直接通过__reduce__协议重建对象。这就会绕开你的单例控制逻辑导致反序列化后得到一个新的、和当前单例完全不同的实例。解决方法是显式处理__reduce__方法class Config(metaclassSingletonMeta): def __init__(self): self.env production def __reduce__(self): # 返回 (类, 构造参数)pickle反序列化时会调用Config() # 而Config()会走元类的__call__最终返回同一个单例 return (Config, ())类似地深拷贝copy.deepcopy也可能产生新实例。如果需要对单例做深拷贝通常建议返回自身也就是在__deepcopy__里写return self。目标是让“复制”动作不破坏单例的唯一性。4.2 子类化的行为差异子类化的坑在__new__方案里最明显。如果用_instance is None判断那么父类和所有子类会共享同一个实例。这在某些场景下是合理的你不希望父类和子类各有一份数据但更多时候会导致子类无法拥有独立状态。如果用元类方案_instances以类本身作为key父类和子类各存各的天然隔离。我自己的实践是允许子类发展的单例类比如一个基础配置类和它的多个子类用元类方案最省心如果就是要严格控制所有后代共享一个实例那需要在__new__里特殊处理但在跨类层级上共享实例这种做法本身就有点违背直觉维护起来容易让人困惑。遇到这种需求我建议先反问一下是不是设计上就不该让子类出现或者干脆别用继承用组合。4.3 测试环境下的单例重置单例最大的天敌之一就是测试。你跑完一个测试用例单例里存了脏数据下一个用例再启动时拿到的是同一个实例测试结果就会互相污染。处理这个问题需要给单例设计一个显式的“重置钩子”。def _reset_singleton(cls): with SingletonMeta._lock: cls._instances.pop(cls, None)在pytest的fixture里可以这样用import pytest from myapp.connection import DatabasePool pytest.fixture(autouseTrue) def reset_db_pool(): yield _reset_singleton(DatabasePool)这段代码会在每个测试用例结束后清空单例的实例缓存保证下一个用例从干净状态开始。要注意这个_reset_singleton函数放在生产代码里可能会被滥用所以我通常放在测试工具模块里不对外暴露。还有更彻底的方式是直接替换_instances字典配合monkeypatch做到无侵入重置但这需要你对元类的内部结构足够熟悉不然容易把正常的单例缓存也清掉。5. 实际项目中的选型建议与经验总结5.1 四种方案怎么选看这张表实现方案核心机制类型是否保留线程安全需自处理推荐场景模块级单例模块缓存是否创建即完成团队内部约定清晰的小项目、配置管理__new__拦截实例构造函数拦截是需自行加锁不想引入元类的小工具类装饰器包装返回函数否需自行加锁只想快速给现有类加单例约束元类__call__拦截是推荐加锁库作者、框架集成、需要子类隔离的复杂场景如果只是自己写脚本用模块级单例和__new__完全够用如果想要一个工程上稳妥、不怕别人误用的方案直接元类一把梭。装饰器适合临时快速处理但类型信息丢失这一点让我在正式项目里不太愿意选它。表格里“线程安全需自处理”的意思是元类和__new__方案如果不处理并发单例可能被破坏而模块级单例因为模块import本身就是进程内原子操作天然安全。5.2 单例是反模式吗每次聊到单例总有人跳出来说它是反模式。我的观点是单例不是反模式滥用才是。它带来的问题本质上是全局可变状态的通病——任何人绕过依赖注入直接访问全局单例都会让模块间的耦合变强。但很多场景里单例恰恰是合理的连接池、日志器、配置对象这些本质上就是进程级的共享资源用单例管理它们比到处new一个更靠谱。Python里还有一个特殊性模块级单例让“单例模式”这个词变得不那么吓人因为你不需要写一大堆样板代码。如果你把一个普通的类定义放在模块顶层并导出实例你实际上就获得了一个Python风格的单例。这种方案比Java式的getInstance()更自然也更符合Python社区的习惯。5.3 我在项目里的实际用法最后分享一个我反复用到的模式用元类单例管理连接池同时给连接池提供显式的reset方法。生产环境里它跑得一直很稳测试环境里reset方法救了我不少次。一个重要的经验是单例类最好一开始就把reset钩子设计进去不要等到写测试的时候再补。因为测试代码往往不愿意动生产类可真到出问题时你又不得不去改它——这种情况我见过太多次了。另外如果项目里已经用了FastAPI或Flask这类框架你也可以考虑用依赖注入而非单例来管理一些组件。依赖注入的好处是伪装成普通参数的传递方便测试时替换成桩实现。但要注意依赖注入不等于实例唯一如果你真的需要一个进程内唯一的连接池最终存储它的地方往往还是一个模块级变量或单例容器。两者可以组合使用不必非此即彼。以我个人踩过几次坑的经验来说单例本身不是难点难点在于后续维护中能不能一直守住“只有一个实例”的约定。锁、序列化、测试重置这些边角细节才是真正区分一个单例实现质量的地方。下一次你在代码里写_instance None的时候不妨多想一步这个单例会不会被多线程同时创建会不会被pickle复制测试的时候怎么重置这些问题想清楚了单例就不再有坑。

相关新闻

Being-H数据加工实战:LeRobot格式、delta动作转换与静态帧裁剪完整指南

Being-H数据加工实战:LeRobot格式、delta动作转换与静态帧裁剪完整指南

【免费下载链接】Being-H Being-H is BeingBeyonds family of human-centric embodied foundation models. 项目地址: https://gitcode.com/gh_mirrors/be/Being-H 点击查看 免费下载 Being-H 是 BeingBeyond 推出的以人为中心的具身基础模型家族,其中 …

2026/10/13 14:49:08 阅读更多 →
CT金属伪影成因与实战抑制指南:从物理原理到工作站实操

CT金属伪影成因与实战抑制指南:从物理原理到工作站实操

1. 项目概述:为什么CT图像里总会出现那些刺眼的“亮条纹”和“黑窟窿” 你有没有在医院拍完CT后,拿到报告单上写着“金属伪影明显,局部组织显示不清”?或者在做牙科CBCT时,看到自己种植牙周围一片雪白发亮、完全看不出…

2026/10/13 14:48:07 阅读更多 →
一维Unet实现ECG波形语义分割:从小波去噪到重叠滑窗推理

一维Unet实现ECG波形语义分割:从小波去噪到重叠滑窗推理

简介:这套基于Unet的ECG分段方案面向心电图信号处理与深度学习初学者,用于自动识别P波、QRS波群和T波分量。作者采用PyTorch实现,结合小波变换将来自QTDB数据集的ECG转换到小波域,并借助WFDB标注完成P段、QRS段、T段的类别划分&am…

2026/10/13 14:48:07 阅读更多 →

最新新闻

电商盗图风险:搜索引擎下载的图片用于商品主图是否侵权

电商盗图风险:搜索引擎下载的图片用于商品主图是否侵权

在电商运营与内容创作中,许多从业者习惯通过搜索引擎直接保存图片作为商品主图或详情页素材。然而,搜索引擎仅作为信息索引工具,并不拥有图片版权,也未获得转授权许可。将来源不明的网络图片直接用于商业展示、广告投放或产品包装…

2026/10/13 15:37:33 阅读更多 →
5人销售团队用AI智能体每月省600小时:OpenRouter架构与实践

5人销售团队用AI智能体每月省600小时:OpenRouter架构与实践

先看一组我们自己算出来时都愣了一下的数字:5个人的销售团队,靠一套内部代号叫 Rasp 的 AI 智能体,每个月省下约600小时的等效工时。当时这个数字报上去,运营负责人第一反应是“你们是不是把等待时间也算进去了”。我说对&#xf…

2026/10/13 15:37:33 阅读更多 →
LiteLLM:统一LLM API调用的轻量级抽象层实战指南

LiteLLM:统一LLM API调用的轻量级抽象层实战指南

1. 项目概述:LiteLLM 是什么,它解决的到底是什么问题? LiteLLM 这个名字刚出现时,我第一反应是“又一个 LLM 封装库?”——毕竟市面上类似工具已经不少,从 LangChain 到 LlamaIndex,再到各种自研…

2026/10/13 15:37:33 阅读更多 →
Open-Code-Review:一种可落地的开源协作契约范式

Open-Code-Review:一种可落地的开源协作契约范式

1. 这不是代码审查工具,而是一套可落地的开源协作契约“open-code-review”这个标题乍看像某个新出的 GitHub Action 或 CLI 工具,但实际翻遍主流包管理器、GitHub Trending 和 Hacker News 近三个月热帖,都找不到一个叫这个名字的成熟项目。…

2026/10/13 15:37:33 阅读更多 →
artcraft:基于Canvas的轻量级创意工具架构与实现

artcraft:基于Canvas的轻量级创意工具架构与实现

1. 项目缘起与整体设计思路1.1 为什么会有 artcraft 这个想法做创意工具这些年,我越来越强烈地感受到一个矛盾:市面上要么是功能极其复杂、学习曲线陡峭的专业软件,要么是简单到只能做几个固定模板的在线工具。中间地带几乎是空白的——那种你…

2026/10/13 15:37:33 阅读更多 →
Docker备份迁移选型指南:save/load、export/import、commit全解析

Docker备份迁移选型指南:save/load、export/import、commit全解析

接手 Docker 环境迁移,或者在给线上容器做备份方案时,很多人第一反应是“把容器打个包带走”。真正到了目标服务器上才发现,docker export导出来的东西和docker save导出来的东西完全不是一回事,而docker commit又像是另一种玄学。…

2026/10/13 15:36:30 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →