python
文章平均质量分 83
Zane199412
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
定义了 __del__ 方法的循环引用对象,为什么曾经死活回收不掉?内存管理连环追问
Day22、Day23 讲了引用计数是主力、分代 GC 是循环引用的兜底、weakref 能从设计上避免循环引用。如果循环引用里的对象还定义了__del__方法,GC 还能正常回收吗?这个问题在 Python 3.4 之前的答案是"不能"——这是一个真实存在过的内存泄漏坑,也是面试里最容易把"背了 GC 三分钟"的人问倒的追问点。原创 2026-09-14 10:56:49 · 122 阅读 · 0 评论 -
两个线程算两遍循环,为什么只快了一点点不是两倍?GIL连环追问
模块四(Day16-21)讲过 GIL、threadingasyncio各自的基础用法,但面试官真正想验证的往往是几个更细的连环追问:threading 面对 CPU 密集型任务到底是"完全没用"还是"效果有限"?asyncio 号称并发,是不是真的只用了一个线程?取消一个协程任务,为什么有时候怎么取消都取消不掉?这几个问题背后都是同一件事——GIL 到底挡住了什么、没挡住什么,今天用实测数据把这几层追问一次讲透。原创 2026-09-11 20:00:00 · 314 阅读 · 0 评论 -
@装饰器包在最外层却拿不到函数?被忽视的调用时机与顺序坑
Day05 写过@property这几个内置装饰器怎么用,但面试官很少满足于"会用",而是喜欢顺着装饰器往下追问:装饰到底发生在什么时候?多个装饰器叠在一起谁先执行?不加到底会丢什么?这些追问背后都是同一件事——装饰器本质上只是一层函数包装,一旦想清楚这一点,所有连环追问都能推导出来,而不用死记结论。原创 2026-09-10 20:00:00 · 253 阅读 · 0 评论 -
明明在赋值前读取,为什么还会报 UnboundLocalError?global 与 nonlocal 深挖
Day04 讲闭包与作用域时提过nonlocal,今天作为面试高频题串讲的第二篇,把globalnonlocal单独拎出来深挖——重点讲一个经常让人摸不着头脑的报错:明明代码是"先读取、后赋值",为什么 Python 会说这个变量"还没被赋值"?原创 2026-09-09 09:32:15 · 156 阅读 · 0 评论 -
257 is 257 为什么是 True?小整数缓存背后还藏着一个更容易被忽略的机制
模块六写完,从今天开始进入模块七——面试高频题串讲,接下来几篇不再引入全新知识点,而是把前面容易被单独拎出来问、又特别容易"感觉懂了但一深挖就露馅"的话题重新过一遍。第一篇是is==257 is 257为什么会是True,而 257 明明已经超出了 -5~256 的缓存范围。原创 2026-09-08 11:24:53 · 405 阅读 · 0 评论 -
只重写了 __eq__,为什么类突然变得不可哈希了?常用魔法方法大盘点
模块六(常用数据结构与标准库进阶)到今天收官。前面几篇分别讲了dictsetfunctools,今天回到一个更基础但经常被忽视的话题——那些让自定义对象能"表现得像内置类型"的魔法方法。重点讲一个真实会踩的坑:只重写__eq__而不管__hash__,Python 会做一件你可能没意识到的事。魔法方法(dunder methods):以双下划线开头结尾的方法,Python 在特定语法操作时会自动调用它们,让自定义类能够像内置类型一样融入 Python 的语法体系。__repr__原创 2026-09-07 20:00:00 · 349 阅读 · 0 评论 -
斐波那契数列加个装饰器,速度快了近五千倍:functools 三件套详解
Day05 讲装饰器时提到过写自定义装饰器要加,但没细讲为什么。今天把functools模块里最常用的三个工具——lru_cachepartialwraps——一次讲透,各自解决的是完全不同类型的问题,别把它们混为一谈。原创 2026-09-07 10:33:29 · 385 阅读 · 0 评论 -
手写“判断key存不存在“的模板代码太烦?一文讲透 collections 四件套
模块里有一批dicttuple的"增强版",几乎每个 Python 项目都会用到。今天把最常用的四个——Counternamedtuple——一次讲透,重点回答一个经常被问到的疑问:Python 3.7 后dict已经有序了,是不是已经没用了?原创 2026-09-04 20:00:00 · 582 阅读 · 0 评论 -
去重用 set 到底能快多少?实测差距接近三百倍
Day26 讲透了dict的哈希表实现,今天讲它的近亲——set。set和dict底层都是哈希表,为什么 3.7 之后dict有序了,set却没有?原创 2026-09-04 11:07:07 · 308 阅读 · 0 评论 -
dict 为什么突然变得有序了?一文讲透哈希表与紧凑字典设计
Python 3.7 之后,dict遍历顺序被正式写进语言规范:一定是按插入顺序。很多人只记住了这个结论,但没搞清楚背后的实现原理——这可不是简单加个"记录顺序"的标记就完事,而是 CPython 团队重新设计了整个哈希表的存储结构。模块六(常用数据结构与标准库进阶)从这里开篇,把dict的底层实现讲透。原创 2026-09-03 20:00:00 · 539 阅读 · 0 评论 -
一个方括号,代价可能是一万五千倍:三个常见性能陷阱实测
模块五(内存管理与性能)到今天收官,把三个流传很广、但很少有人真正实测过的性能话题一次讲清楚:字符串+=拼接优化的真实边界在哪、"全局变量转局部变量更快"这条老经验现在还成不成立、以及一个看起来无关紧要的方括号,为什么在某些场景下能造成上万倍的性能差距。原创 2026-09-03 11:25:50 · 340 阅读 · 0 评论 -
你以为的性能瓶颈,未必是真的瓶颈:用 cProfile 找到真凶
写代码的人对"哪里慢"通常都有一种直觉,习惯性地怀疑那些看起来循环次数多、计算量大的代码。这种直觉经常是错的,真正的瓶颈可能藏在一行毫不起眼的代码里。找瓶颈不该靠猜,该靠cProfile。原创 2026-09-02 20:00:00 · 221 阅读 · 0 评论 -
只改一个方向的引用,循环引用就能立刻被回收?一文讲透 weakref 弱引用
Day22 讲了循环引用要靠兜底才能清理,del完对象却"卡"在内存里不动。今天这篇往前一步:能不能从设计上直接避免循环引用产生,而不是每次都指望 GC 事后来擦屁股?答案是weakref——一种不增加引用计数的引用方式。原创 2026-09-02 10:14:51 · 314 阅读 · 0 评论 -
为什么 del 一个对象有时立刻消失,有时却纹丝不动?一文讲透引用计数与垃圾回收
模块四把并发编程讲完了,从今天开始进入模块五——内存管理与性能。第一篇先解决一个基础但很多人说不清楚的问题:Python 的对象到底是怎么被回收的?为什么有时候del一个对象立刻就触发了销毁,有时候明明del了却好像什么都没发生?答案就在引用计数和垃圾回收这两套机制的分工里。原创 2026-09-01 20:00:00 · 374 阅读 · 0 评论 -
threading、multiprocessing、asyncio 到底怎么选?一张图 + 三组实测数据说清楚
Day16 到 Day20 分别把 GIL、多线程、多进程、asyncio 协程逐个讲透了,模块四的收官篇把这三种并发方案放到同一套 benchmark 下直接对比——不是空谈"该用哪个",而是用实测数据和一张决策图,把选择标准钉死。原创 2026-09-01 12:07:08 · 361 阅读 · 0 评论 -
create_task 和直接 await 到底有什么不一样?asyncio 的 Task、gather 与并发数量控制
Day19 用让两个协程并发跑了起来,但没细说gather背后到底发生了什么。今天把Taskgather的工作原理讲透,再补上实战中绕不开的两个问题:并发数量怎么控制(不能无限制地同时发起几千个请求),以及某个任务出错时该怎么处理。原创 2026-08-31 20:00:00 · 296 阅读 · 0 评论 -
调用了 async 函数却没执行?一文讲透协程、event loop 与 await
Day17、Day18 分别讲了多线程和多进程,两者都是"重量级"的并发方案——线程有 GIL 限制,进程有创建开销和内存隔离。面对成千上万个 I/O 密集型任务(比如同时发出几千个网络请求),这两种方案都不够轻便。今天讲的asyncio协程,就是专门为这种场景设计的更轻量的并发方式。原创 2026-08-31 10:48:53 · 383 阅读 · 0 评论 -
多线程绕不开 GIL,多进程凭什么能绕开?一文讲透 multiprocessing
Day16、Day17 反复验证了一个结论:CPU 密集型任务用多线程没有加速效果,因为 GIL 让同一时刻只有一个线程能执行 Python 字节码。那如果真的需要用 Python 做并行计算,出路在哪?答案是——今天这篇讲清楚它凭什么能绕开 GIL,以及绕开之后要付出什么新的代价。原创 2026-08-29 20:17:39 · 200 阅读 · 0 评论 -
daemon 线程说没就没?一文讲透 threading 的适用场景与线程安全
Day16 讲透了 GIL,结论是"CPU 密集型任务用多线程没有加速效果,I/O 密集型任务才是 threading 的用武之地"。今天这篇就在这个结论之上,把threading模块实际怎么用讲清楚——从创建线程的两种写法,到 daemon 线程消失的坑,再到死锁怎么产生、怎么用锁避免,最后落到更现代的写法。原创 2026-08-29 20:04:36 · 198 阅读 · 0 评论 -
多开几个线程,为什么算数字反而没变快?一文讲透 CPython 的 GIL
模块三讲完面向对象进阶,从今天开始进入 Python 面试里问法最刁钻的部分——GIL 与并发编程。第一篇先把最基础也最容易被问到的问题讲透:GIL 到底是什么,为什么大家都说 Python 的多线程是"假并发"。这一篇会用实测数据说话,而不是空谈概念。原创 2026-08-28 20:00:00 · 288 阅读 · 0 评论 -
没有 interface 关键字,Python 怎么做接口约束?鸭子类型与 abc 抽象基类讲透
如果它走起来像鸭子、叫起来像鸭子,那它就是鸭子”——这是 Python 鸭子类型最经典的比喻,也是 Python 没有interface关键字却依然能优雅处理"接口"这件事的核心思路。但灵活是有代价的:鸭子类型的约束是隐式的、运行时的,出问题往往要等到调用那一刻才暴露。今天这篇把鸭子类型和用来弥补它的abc抽象基类一次讲透,也算是给模块三(面向对象进阶)系列画上句号。passdef describe(self): # 不是抽象方法,是具体实现return f"这个图形的面积是。原创 2026-08-28 14:33:10 · 312 阅读 · 0 评论 -
类也是对象?一文讲透元类 metaclass 这件“深度魔法“
Python 里"万物皆对象"这句话,很多人只理解到"实例是对象"这一层,其实还有更深一层:**类本身也是对象**。既然是对象,就一定是由某个"类"创建出来的——创建类的这个东西,就是今天要讲的元类(metaclass)。原创 2026-08-27 20:00:00 · 184 阅读 · 0 评论 -
钻石继承调用哪个方法?一文讲透 MRO 与 C3 线性化算法
如果一个类同时继承了两个父类,而这两个父类又都继承自同一个祖先类,调用一个三方都定义过的同名方法,到底会执行谁的实现?这是多重继承下最经典的疑问,也是 `super()` 最容易被误解的地方——很多人以为 `super().method()` 调用的是"我的父类",但在多重继承场景下,事实往往不是这样。原创 2026-08-27 15:08:24 · 287 阅读 · 0 评论 -
`ClassName()` 只是一步?拆开看 `__new__` 和 `__init__` 各自在干什么
`ClassName(...)` 这行代码看起来是"一步创建对象",实际上背后拆成了两个独立的阶段。上一篇讲类变量和实例变量,本质是"属性归谁"的问题;今天这篇往前退一步,讲清楚一个对象到底是怎么"被造出来"的——`__new__` 和 `__init__` 各自负责什么,以及这个区分在单例模式、不可变类型子类化里为什么会变得很关键。原创 2026-08-26 19:00:00 · 542 阅读 · 0 评论 -
类变量与实例变量:一个共享列表引发的线上事故
模块二函数式编程系列写完,今天开始模块三面向对象进阶。第一篇讲一个看起来很基础、但几乎人人都踩过的坑:类变量和实例变量分不清楚,尤其是用可变类型(`list`/`dict`)当类变量时,本意是"每个实例一份独立数据",结果却是所有实例共享同一份——这跟 Day01 讲的可变默认参数陷阱其实是同一类问题的两种变体。原创 2026-08-26 14:42:41 · 271 阅读 · 0 评论 -
map 比推导式快“是真的吗?一文讲透 map、filter、reduce 与 lambda 的真实性能与设计取舍
函数式编程里最常被提起的三个工具——`map`、`filter`、`reduce`——配合 `lambda` 几乎能把很多数据处理逻辑压缩成一行。但压缩成一行不代表就该这么写:`reduce` 在 Python 3 里被移出了内置命名空间,这背后有一段挺有意思的设计取舍。今天这篇把这三个高阶函数和 `lambda` 一次讲透,顺便用实测数据推翻一个流传很广的性能误解。原创 2026-08-25 16:00:00 · 132 阅读 · 0 评论 -
[] 和 () 就差一个括号?一文讲透列表推导式与生成器表达式的真实性能差异
`[x for x in range(5)]` 和 `(x for x in range(5))`,看起来只差一个括号,很多人会以为这只是风格偏好,随便选一个都行。但这一个括号的差异,背后是"立即计算全部结果"和"惰性求值"两种完全不同的运行方式——上一篇讲生成器为什么省内存,今天就把这个省内存的特性,和它最常被拿来对比的列表推导式放在一起,讲清楚到底该怎么选、又容易踩哪些坑。原创 2026-08-25 10:48:05 · 360 阅读 · 0 评论 -
同样十万个元素,为什么生成器只占列表的四千分之一内存?一文讲透 yield 与 yield from
如果要处理一个几十 GB 的大文件,或者生成一个理论上无穷的数字序列,用 `list` 来存结果,内存会直接被撑爆。但同样是"逐个产出一系列值",生成器却能做到几乎不占内存——这背后的机制就是今天要讲的 `yield`。原创 2026-08-24 20:00:00 · 613 阅读 · 0 评论 -
同一个 list 为什么能被两个 for 循环同时遍历?一文讲透可迭代对象与迭代器的真相
同一个 `list`,可以同时被两个 `for` 循环遍历,各自互不干扰——一个循环遍历到第二个元素了,另一个循环依然能从头开始。这背后其实藏着一个经常被忽略的设计:**你手里的这个 `list`,和 `for` 循环真正用来遍历的东西,根本不是同一个对象。**原创 2026-08-24 14:44:33 · 425 阅读 · 0 评论 -
别再手写 try/finally 了:一文讲透 with 语句背后的上下文管理器协议
打开一个文件忘了关、拿到一把锁忘了释放、建立的数据库连接忘了断开——这些资源泄漏问题,本质上都是同一类疏忽:**清理逻辑写在了一个可能被跳过的地方**。手写 `try/finally` 当然能解决,但前提是你每次都记得写、而且写对了位置。原创 2026-08-22 19:00:00 · 311 阅读 · 0 评论 -
@property 到底是怎么把方法伪装成属性的?一文吃透 property、staticmethod、classmethod
假设你写了一个 `Person` 类,`age` 是个普通属性,调用方到处都在写 `p.age = 30` 这样的赋值。有一天产品说年龄不能是负数,你想加一个校验——但如果把 `age` 改成 `set_age()` 方法,之前所有 `p.age = xxx` 的调用代码都得跟着改,这个成本谁都不想承担。原创 2026-08-22 13:59:20 · 221 阅读 · 0 评论 -
闭包到底“闭“住了什么?一文讲透 LEGB 规则与循环里的闭包陷阱
函数执行完毕之后,它内部的局部变量不是应该被销毁吗?可现实是,你经常能看到这样的代码:一个函数返回了另一个函数,外层函数明明早就执行完了,返回的那个内层函数却还能一直访问、甚至修改外层函数的变量,就像外层函数从没消失过一样。这就是**闭包**。今天这篇从 Python 变量查找的底层规则 LEGB 讲起,把闭包的原理讲透,再顺带拆解一个几乎人人都踩过的经典坑——**循环里创建的多个闭包,为什么最后拿到的全是同一个值**。原创 2026-08-20 10:46:55 · 319 阅读 · 0 评论 -
Python 灵活参数的终极奥义:*args、**kwargs 到底在干什么?
你一定写过 `print("a", "b", "c")`,也一定见过 `dict(a=1, b=2, c=3)`——这些内置函数明明能接受任意数量的参数,而你自己写的函数,参数个数一旦定死了就只能定死。原创 2026-08-19 11:10:48 · 228 阅读 · 0 评论 -
copy 和 deepcopy 到底在拷贝什么?一文讲清赋值、浅拷贝、深拷贝的引用关系
上一篇讲了可变默认参数的坑,本质是"该新建对象却没新建,所有调用共享同一份数据"。今天这篇更进一步:**就算你主动写了"拷贝"代码,如果没搞清楚拷贝的层级,一样会踩到几乎一模一样的坑。**最典型的场景:你想复制一份配置字典留着自己改,用了 `config.copy()`,结果改着改着发现,线上那份"原始配置"也被你悄悄改了。这不是 bug,是你对 `copy()` 到底复制了什么层级,理解错了。原创 2026-08-18 10:55:05 · 327 阅读 · 0 评论 -
可变对象 vs 不可变对象:为什么“可变默认参数“是 Python 最经典的坑?
如果你写过一段时间 Python,大概率遇到过这种诡异 bug:一个看起来完全无状态的函数,第二次调用的结果却"记得"第一次调用的数据,明明每次都是新调用,却像是共享了一个全局变量。这就是 Python 最经典的入门陷阱——**可变默认参数**。今天这篇从"可变 vs 不可变对象"这个更底层的概念讲起,把这个坑的成因彻底讲透,顺便理清 `is` 和 `==` 这对最容易被面试官盯上的操作符。原创 2026-08-17 17:44:01 · 270 阅读 · 0 评论
分享