Python:类变量 vs 全局变量 ------ 查找路径区别
Python 名字查找遵循两套独立规则:作用域链(用于普通变量名) 、属性查找链(用于对象。属性)
一、全局变量的查找路径(名字查找:单纯变量名,不带 .)
g = 100
def foo():
print(g)
查找顺序(LEGB 规则):
- L Local :当前函数局部命名空间 → 找
g - E Enclosing :外层嵌套函数闭包命名空间 → 找
g - G Global :当前模块命名空间(模块
__dict__) → 找到全局变量g - B Builtin :内置命名空间(
builtins)
关键点:
- 全局变量属于名字空间查找,是 LEGB;
- 只在写操作的时候需要
global声明,告诉解释器不要新建局部变量,去 G 层修改。
二、类变量的查找路径(属性查找,一定带 .)
类变量存在类对象的__dict__,访问分两种写法:
写法 1:类名.属性 例如 A.x
- 取类对象
A - 在
A.__dict__直接查找x - 找不到就沿着继承链(MRO) 向上找父类的
__dict__
不会走到模块全局命名空间!
写法 2:实例.属性 例如 a.x(最常用,坑最多)
class A:
x = 200
a = A()
print(a.x)
属性查找顺序(obj.__getattr__ 默认逻辑):
- 实例
a.__dict__:先看实例自己有没有x - 如果实例没有,再去**类
A.__dict__**查找类变量 - 还找不到,沿着 MRO 向上遍历所有父类
- 全部找不到抛出
AttributeError
⚠️ 重点:
a.x = 999是往实例__dict__写入 ,不会修改类变量 。之后读取a.x直接读到实例字典的值,不再访问类变量。
三、核心对比:两条完全不同的查找体系
- 全局变量:LEGB 名字查找,是解析器对裸变量名(不带点)的解析规则。
- 类变量:属性查找(
.操作符) ,是对象属性的查找规则,不走 LEGB。
举个例子区分两者:
x = 10 # 全局变量
class A:
x = 20 # 类变量
a = A()
print(x) # 裸名,LEGB → 全局x=10
print(A.x) # .属性查找 → 类A的x=20
print(a.x) # .属性查找 → 实例无x,找到类A.x=20
四、查找路径对比表
表格
| 项目 | 全局变量(裸变量名) | 类变量(obj.x/ Class.x) |
|---|---|---|
| 查找体系 | LEGB 名字作用域链 | 对象属性查找链 + MRO 继承链 |
| 查找顺序 | 局部 → 闭包 → 模块全局 → builtin | 实例 dict → 当前类 dict → MRO 父类链 |
| 存储位置 | 模块__dict__ |
类__dict__ |
| 是否经过继承链 | ❌ 不涉及继承 | ✅ 会沿着 MRO 父类向上查找 |
| 查找触发 | 直接写变量名(不带.) |
使用 . 属性访问运算符 |
| 会不会跑到 builtin | ✅ LEGB 最后一层是 builtin | ❌ 属性查找默认不走 builtin 命名空间 |
五、容易混淆的场景
x = 1
class A:
x = 2
def func(self):
print(x) # 裸名!LEGB,取全局x=1
print(self.x) # .属性查找,类变量x=2
这里
print(x)和print(self.x)完全不是一条查找路线,很多人踩坑!
六、性能层面补充
- 裸名全局变量:需要走完 LEGB,相对慢
类名.属性:直接查类 dict,查找路径短,更快mp.qingtianyu.cn/blog/9kLm2QpX7a.html
mp.qingtianyu.cn/blog/Zx4Tn8Vr1B.html
mp.qingtianyu.cn/blog/Qw7Yh3Ns5D.html
mp.qingtianyu.cn/blog/Mc2Jv9Kp6E.html
mp.qingtianyu.cn/blog/Rt8Bn4Xz0F.html
mp.qingtianyu.cn/blog/Hg5Lp1Wq7G.html
mp.qingtianyu.cn/blog/Uv3Dm6Yr2H.html
mp.qingtianyu.cn/blog/Pa9Kc4Nt8J.html
mp.qingtianyu.cn/blog/Se2Qx7Vb5K.html
mp.qingtianyu.cn/blog/Fn6Wm1Zp3L.html
mp.qingtianyu.cn/blog/Yd4Hr9Cv2M.html
mp.qingtianyu.cn/blog/Jk7Tq3Bs8N.html
mp.qingtianyu.cn/blog/Ol1Pm5Xw6P.html
mp.qingtianyu.cn/blog/Bg8Nc2Vr4Q.html
mp.qingtianyu.cn/blog/Xm5Kt7Yd1R.html
mp.qingtianyu.cn/blog/Cv9Qp3Ln6S.html
mp.qingtianyu.cn/blog/Zr2Wm8Hx4T.html
mp.qingtianyu.cn/blog/Nk6Jd1Vp9U.html
mp.qingtianyu.cn/blog/Lq4Yt7Bc2V.html
mp.qingtianyu.cn/blog/Wp8Rm3Nx5W.html
mp.qingtianyu.cn/blog/Td1Kv6Qs9X.html
mp.qingtianyu.cn/blog/Hx5Pm2Zr7Y.html
mp.qingtianyu.cn/blog/Gc9Bn4Wt1Z.html
mp.qingtianyu.cn/blog/Vr3Lq8Jd6A.html
mp.qingtianyu.cn/blog/Mp7Yx2Kc5B.html
mp.qingtianyu.cn/blog/Ks4Wm9Nv3C.html
mp.qingtianyu.cn/blog/Qn1Rt6Bp8D.html
mp.qingtianyu.cn/blog/Dz5Jv2Xm7E.html
mp.qingtianyu.cn/blog/Sb9Lq4Hr1F.html
mp.qingtianyu.cn/blog/Yt3Pm8Kx6G.html
mp.qingtianyu.cn/blog/Rc7Wn1Vd4H.html
mp.qingtianyu.cn/blog/Bp2Qx9Lm5J.html
mp.qingtianyu.cn/blog/Nv6Tr3Yc8K.html
mp.qingtianyu.cn/blog/Lm1Jd7Wp2L.html
mp.qingtianyu.cn/blog/Xq5Kv9Bn4M.html
mp.qingtianyu.cn/blog/Ct8Rm2Hx7N.html
mp.qingtianyu.cn/blog/Zp3Yq6Ld1P.html
mp.qingtianyu.cn/blog/Gv9Wm4Nc5Q.html
mp.qingtianyu.cn/blog/Hk2Jx7Rt8R.html
mp.qingtianyu.cn/blog/Md6Pq1Bv3S.html
mp.qingtianyu.cn/blog/Tn8Lm5Wx2T.html
mp.qingtianyu.cn/blog/Qr4Yp9Kc7U.html
mp.qingtianyu.cn/blog/Vx1Jv6Nd3V.html
mp.qingtianyu.cn/blog/Kp7Wm2Ht9W.html
mp.qingtianyu.cn/blog/Bc5Rq8Lx4X.html
mp.qingtianyu.cn/blog/Nm9Yd3Pv1Y.html
mp.qingtianyu.cn/blog/Lt2Kx7Bc6Z.html
mp.qingtianyu.cn/blog/Xv8Qm4Nr5A.html
mp.qingtianyu.cn/blog/Cp1Jd9Wt3B.html
mp.qingtianyu.cn/blog/Zk6Lq2Yx8C.html
mp.qingtianyu.cn/blog/Gr3Pm7Vc1D.html
mp.qingtianyu.cn/blog/Hx9Bn5Kd4E.html
mp.qingtianyu.cn/blog/Mv2Tq8Lm6F.html
mp.qingtianyu.cn/blog/Tc7Yp1Rx3G.html
mp.qingtianyu.cn/blog/Qm4Jv9Wd5H.html
mp.qingtianyu.cn/blog/Vp8Km2Nx7J.html
mp.qingtianyu.cn/blog/Kd1Lq6Bt9K.html
mp.qingtianyu.cn/blog/Bx5Rm3Yc2L.html
mp.qingtianyu.cn/blog/Nq9Pv7Hd4M.html
mp.qingtianyu.cn/blog/Lm3Jx1Wt6N.html
mp.qingtianyu.cn/blog/Xc8Qm5Bv2P.html
mp.qingtianyu.cn/blog/Cv4Kd9Nr7Q.html
mp.qingtianyu.cn/blog/Zp1Yq6Lx3R.html
mp.qingtianyu.cn/blog/Gt7Wm2Vc9S.html
mp.qingtianyu.cn/blog/Hk5Jv8Rd1T.html
mp.qingtianyu.cn/blog/Mx9Pq3Bn6U.html
mp.qingtianyu.cn/blog/Tm2Ld7Wv4V.html
mp.qingtianyu.cn/blog/Qc6Yp1Kx8W.html
mp.qingtianyu.cn/blog/Vr3Jm9Nt5X.html
mp.qingtianyu.cn/blog/Kp8Qv4Bd2Y.html
mp.qingtianyu.cn/blog/Bm1Lx6Wc7Z.html
mp.qingtianyu.cn/blog/Nv5Rd9Yp3A.html
mp.qingtianyu.cn/blog/Lq2Km7Jx8B.html
mp.qingtianyu.cn/blog/Xt9Pm4Vc1C.html
mp.qingtianyu.cn/blog/Cd3Qv8Bn6D.html
mp.qingtianyu.cn/blog/Zx7Lp2Yr5E.html
mp.qingtianyu.cn/blog/Gm1Jd6Wv9F.html
mp.qingtianyu.cn/blog/Hv4Kq9Nx2G.html
mp.qingtianyu.cn/blog/Mp8Rm3Bc7H.html
mp.qingtianyu.cn/blog/Tq1Yv5Ld4J.html
mp.qingtianyu.cn/blog/Qx6Jm2Wt9K.html
mp.qingtianyu.cn/blog/Vc3Pq7Rn1L.html
mp.qingtianyu.cn/blog/Km9Ld4Bv6M.html
mp.qingtianyu.cn/blog/Bp2Xv8Yc3N.html
mp.qingtianyu.cn/blog/Nr5Qm1Jx7P.html
mp.qingtianyu.cn/blog/Lv8Kd3Wt2Q.html
mp.qingtianyu.cn/blog/Xm4Pq9Bc6R.html
mp.qingtianyu.cn/blog/Ct1Rv7Lx5S.html
mp.qingtianyu.cn/blog/Zp8Jm2Yd4T.html
mp.qingtianyu.cn/blog/Gq3Kv6Nx9U.html
mp.qingtianyu.cn/blog/Hm7Ld1Wc5V.html
mp.qingtianyu.cn/blog/Mv4Pq8Bt2W.html
mp.qingtianyu.cn/blog/Tr9Ym3Jx6X.html
mp.qingtianyu.cn/blog/Qc2Kv7Ld1Y.html
mp.qingtianyu.cn/blog/Vp6Rm4Nc8Z.html
mp.qingtianyu.cn/blog/Kx1Jd9Wv3A.html
mp.qingtianyu.cn/blog/Bm5Qq2Yt7B.html
mp.qingtianyu.cn/blog/Nc8Lm4Hx1C.html
mp.qingtianyu.cn/blog/Lv3Pq9Rd6D.html
mp.qingtianyu.cn/blog/Xt7Km2Bc5E.html实例.属性:优先查实例 dict;实例没有才上类,多一次字典查询
性能差距很小;热点循环统一缓存到局部变量是最优方案。
如果你想,我可以用dis字节码,打印两种查找对应的底层字节指令,直观看到查找过程。