96SEO 2026-08-14 22:26 0
模块二函数式编程系列写完,今天开始模块三面向对象进阶。第一篇讲一个看起来很基础、但几乎人人都踩过的坑:类变量和实例变量分不清楚,特别是用可变类型当类变量时本意是“每个实例一份独立数据”。结果却是所有实例共享同一份——这跟 Day01 讲的可变默认参数陷阱其实是同一类问题的两种变体。

使用者痛点:很多同学在调试代码时发现,两个看似独立的对象居然互相影响,却找不到根本原因。
__init__ 之外的属性。归类本身所有,所有实例共享同一份数据。话说回来,__init__里通过 self.attr = … 赋值创建的属性。归每个实例自己所有,互不干扰。
class Employee:
company = "ByteDance" # 类变量:所有 Employee 实例共享
def __init__:
self.name = name # 实例变量:每个实例独立一份
使用者痛点:遇到「某个对象的属性莫名其妙被别的对象改了」时不知道该去哪里追踪根源。
instance.attr 的查找顺序很明确:先查实例自己的 __dict__没有再沿着类的 MRO 往上查找类变量。都没找到才抛 AttributeError. 这个顺序解释了类变量“共享”的本质——它只在类的 __dict__`里存了一份,所有没有同名实例变量的对象都会读取到这同一份。
类变量存在的意义很直接:给所有实例共享配置、常量、计数器这类“不需要每个实例各存一份” 的数据,省内存也表达了语义上的“这是类级别的东西”。问题出在可变类型上:如果把 list/dict) 当作类变量。又用原地修改方式操作它(比如 self.items.append),并不会触发“实例遮蔽”的赋值分支,所有实例修改的其实是同一个底层对象——这正是很多“线上事故”的起点。
flowchart LR
A --> B{实例字典里
有该属性吗}
B -- 有 --> C
B -- 没有 --> D
D --> E
D --> F
使用者痛点:误以为给某个对象赋值会全局生效,却导致意外的数据覆盖。
e1 = Employee
e2 = Employee
print # ByteDance ByteDance
# 修改类变量本身
Employee.company = "TikTok"
print # TikTok TikTok —— 两个实例都变了
# 给 e1 创建同名实例变量
e1.company = "Alice's own"
print # {'name': 'Alice'。'company': "Alice's own"}
print # Alice's own TikTok —— e1 有了自己的 company,e2 仍读类变量
print # TikTok —— 类变量本身没被 e1 那行改动
instance.attr = value 永远只会操作实例自己的 `__dict__`**,绝不会修改类变量——这也是为什么它叫“遮蔽”而不是“修改”。想改动真正的类级别数据,需要通过 ClassName.attr = value.
使用者痛点:"购物车竟然跨使用者共用了商品列表!" 这种 bug 常常让产品经理抓狂。
class ShoppingCart: items = # 本意是给每个购物车一个空列表;实际是所有购物车共享同一个 list 对象 def add: self.items.append # 原地修改,不是赋值,不会创建实例变量 cart1 = ShoppingCart cart2 = ShoppingCart cart1.add print # —— cart2 什么都没做,却多了个苹果
The culprit is line self.items.append: it mutates shared list in place. Because re is no assignment to
The fix is straightforward – create a fresh list for each instance inside
class ShoppingCart: def __init__: self.items = # 每个实例拥有自己的列表 def add: self.items.append
User Pain Point:"员工数量明明应该递增。却总是停在 0",让业务监控报错。
class Employee: count = 0 # 类级别计数器 def __init__: self.name = name self.count += 1 # 错误写法!等价于 self.count = self.count + 1 # → 在此行后每个实例都有自己的 `count` 实例属性,与类计数器脱钩 e1 = Employee e2 = Employee print # 0 —— 类计数器根本没有被更新 print # 1 1 —— 看似正常。但已经不是同一个计数器了
The expression
This shadows original class variable for that particular instance. Subsequent “+=” operations only affect shadowed instance attribute.
The correct way is to modify class variable explicitly:
class Employee: count = 0 def __init__: self.name = name Employee.count += 1 # 明确操作的是类级别计数器print # 2
python print # Only contains instance attributes print.__dict__) # Contains class attributesIf an attribute appears only in
type.__dict__,it’s a class variable;if it’s ininstance.__dict__,it’s an instance variable.四、面试追问
先检查
instance.__dict__;若未命中则沿 MRO 向上搜索其所属 Class 的__dict__;若仍未找到则抛AttributeError. 而instance.attr = value始终只写入当前对象的__dict__,不会改动任何父层级中的同名属性。因为原地修改不涉及对
self.attr的赋值动作,所以不会触发 “为该对象创建新条目” 的分支。所有对象仍然指向同一个底层可变对象,从而导致跨实例的数据污染。这正是 “可变默认参数” 陷阱在 OOP 场景下的延伸。读取阶段使用的是 Class Variable;写入阶段却在当前 Instance 的
__dict__中新建同名属性,从此脱钩。正确做法是显式使用 Class 名称进行累加,例如Employee.count += 1.检查
instance.__dict__和type.__dict__。若两者均无,则继续沿 MRO 向上查父类。下一篇预告
Dаy12 将讲解 `
` __new`` vs ` ` __init``——对象创建实际为两个阶段。` ` __new``负责真正“造出”这个对象,而 ` ` __init``只负责初始化。这一区别在单例模式、不可变对象等高级场景里尤为关键。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback