Python:类变量 vs 全局变量 ------ 隔离性对比
隔离性:指不同代码 / 线程 / 模块之间,状态会不会互相干扰、会不会意外篡改、影响范围多大。
1. 全局变量:模块级,隔离很差
全局变量归属模块命名空间。 只要是同一个模块里的代码,不管函数、线程,全都共享这一份全局字典。
-
作用域:整个模块内无差别共享
-
隔离单位:模块。不同模块之间的全局变量天然隔离;但同一模块内完全不隔离。
-
风险:任意函数都可以读取、修改(只要加 global)。一处修改,模块内所有地方全部生效。
-
污染:很容易发生命名冲突 。比如你定义了
count全局变量,另一个函数不小心也用count,直接覆盖。module.py
count = 0 # 全局变量,本模块所有函数共享
def func1():
global count
count +=1def func2():
global count
count +=1
func1 和 func2 修改的是同一个count,相互影响。想做多组独立计数器 ,只能手动定义多个全局变量count1/count2,管理麻烦。
2. 类变量:类级别,隔离更好
类变量归属类对象 ,隔离单位是类。
-
不同的类,类变量互相独立、互不干扰;
-
同一个类的所有实例,共享本类的类变量;
-
天然支持分组隔离:一组共享状态放到一个类,另一组放到另一个类。
class CounterA:
count = 0class CounterB:
count = 0CounterA.count +=1
print(CounterA.count) # 1
print(CounterB.count) # 0 互不影响!
两个类都叫
count,但属于不同类对象,不会命名冲突。这就是类变量的隔离优势。
⚠️ 注意:同一个类的所有实例之间不隔离,共用同一份类变量。
class Counter:
count = 0
c1 = Counter()
c2 = Counter()
Counter.count +=1
print(c1.count, c2.count) # 两个实例读到同一个值
3. 多线程场景下的隔离性
- 全局变量:同模块所有线程共享同一份数据,一旦并发写,全部线程受影响。没有分组能力,所有线程共用一套状态。
- 类变量 :
- 不同类:天然隔离,可以把不同业务的共享状态分到不同类,互不干扰;
- 同类:多线程依然共享同一个类变量,并发写同样存在竞态,依然需要锁。
✅ 隔离 ≠ 线程安全!隔离只是 "A 组状态不会污染 B 组",不是并发写自动安全。
4. 命名隔离(命名冲突)
-
全局变量:同模块不能重名,后面定义直接覆盖前面。
x = 10
x = 20 # 直接覆盖全局x -
类变量:不同类内部可以同名属性,互不冲突。
class A:
x = 10
class B:
x = 20A.x 和 B.x 完全独立
5. 封装隔离(访问控制)
Python 没有真正私有变量,但约定上:
-
全局变量:几乎没有封装,模块内任何地方随便访问修改,很难限制读写。
-
类变量:可以和方法、mp.ketengxin.com/blog/9kLm2QpX7a.html
mp.ketengxin.com/blog/Zx4Tn8Vr1B.html
mp.ketengxin.com/blog/Qw7Yh3Ns5D.html
mp.ketengxin.com/blog/Mc2Jv9Kp6E.html
mp.ketengxin.com/blog/Rt8Bn4Xz0F.html
mp.ketengxin.com/blog/Hg5Lp1Wq7G.html
mp.ketengxin.com/blog/Uv3Dm6Yr2H.html
mp.ketengxin.com/blog/Pa9Kc4Nt8J.html
mp.ketengxin.com/blog/Se2Qx7Vb5K.html
mp.ketengxin.com/blog/Fn6Wm1Zp3L.html
mp.ketengxin.com/blog/Yd4Hr9Cv2M.html
mp.ketengxin.com/blog/Jk7Tq3Bs8N.html
mp.ketengxin.com/blog/Ol1Pm5Xw6P.html
mp.ketengxin.com/blog/Bg8Nc2Vr4Q.html
mp.ketengxin.com/blog/Xm5Kt7Yd1R.html
mp.ketengxin.com/blog/Cv9Qp3Ln6S.html
mp.ketengxin.com/blog/Zr2Wm8Hx4T.html
mp.ketengxin.com/blog/Nk6Jd1Vp9U.html
mp.ketengxin.com/blog/Lq4Yt7Bc2V.html
mp.ketengxin.com/blog/Wp8Rm3Nx5W.html
mp.ketengxin.com/blog/Td1Kv6Qs9X.html
mp.ketengxin.com/blog/Hx5Pm2Zr7Y.html
mp.ketengxin.com/blog/Gc9Bn4Wt1Z.html
mp.ketengxin.com/blog/Vr3Lq8Jd6A.html
mp.ketengxin.com/blog/Mp7Yx2Kc5B.html
mp.ketengxin.com/blog/Ks4Wm9Nv3C.html
mp.ketengxin.com/blog/Qn1Rt6Bp8D.html
mp.ketengxin.com/blog/Dz5Jv2Xm7E.html
mp.ketengxin.com/blog/Sb9Lq4Hr1F.html
mp.ketengxin.com/blog/Yt3Pm8Kx6G.html
mp.ketengxin.com/blog/Rc7Wn1Vd4H.html
mp.ketengxin.com/blog/Bp2Qx9Lm5J.html
mp.ketengxin.com/blog/Nv6Tr3Yc8K.html
mp.ketengxin.com/blog/Lm1Jd7Wp2L.html
mp.ketengxin.com/blog/Xq5Kv9Bn4M.html
mp.ketengxin.com/blog/Ct8Rm2Hx7N.html
mp.ketengxin.com/blog/Zp3Yq6Ld1P.html
mp.ketengxin.com/blog/Gv9Wm4Nc5Q.html
mp.ketengxin.com/blog/Hk2Jx7Rt8R.html
mp.ketengxin.com/blog/Md6Pq1Bv3S.html
mp.ketengxin.com/blog/Tn8Lm5Wx2T.html
mp.ketengxin.com/blog/Qr4Yp9Kc7U.html
mp.ketengxin.com/blog/Vx1Jv6Nd3V.html
mp.ketengxin.com/blog/Kp7Wm2Ht9W.html
mp.ketengxin.com/blog/Bc5Rq8Lx4X.html
mp.ketengxin.com/blog/Nm9Yd3Pv1Y.html
mp.ketengxin.com/blog/Lt2Kx7Bc6Z.html
mp.ketengxin.com/blog/Xv8Qm4Nr5A.html
mp.ketengxin.com/blog/Cp1Jd9Wt3B.html
mp.ketengxin.com/blog/Zk6Lq2Yx8C.html
mp.ketengxin.com/blog/Gr3Pm7Vc1D.html
mp.ketengxin.com/blog/Hx9Bn5Kd4E.html
mp.ketengxin.com/blog/Mv2Tq8Lm6F.html
mp.ketengxin.com/blog/Tc7Yp1Rx3G.html
mp.ketengxin.com/blog/Qm4Jv9Wd5H.html
mp.ketengxin.com/blog/Vp8Km2Nx7J.html
mp.ketengxin.com/blog/Kd1Lq6Bt9K.html
mp.ketengxin.com/blog/Bx5Rm3Yc2L.html
mp.ketengxin.com/blog/Nq9Pv7Hd4M.html
mp.ketengxin.com/blog/Lm3Jx1Wt6N.html
mp.ketengxin.com/blog/Xc8Qm5Bv2P.html
mp.ketengxin.com/blog/Cv4Kd9Nr7Q.html
mp.ketengxin.com/blog/Zp1Yq6Lx3R.html
mp.ketengxin.com/blog/Gt7Wm2Vc9S.html
mp.ketengxin.com/blog/Hk5Jv8Rd1T.html
mp.ketengxin.com/blog/Mx9Pq3Bn6U.html
mp.ketengxin.com/blog/Tm2Ld7Wv4V.html
mp.ketengxin.com/blog/Qc6Yp1Kx8W.html
mp.ketengxin.com/blog/Vr3Jm9Nt5X.html
mp.ketengxin.com/blog/Kp8Qv4Bd2Y.html
mp.ketengxin.com/blog/Bm1Lx6Wc7Z.html
mp.ketengxin.com/blog/Nv5Rd9Yp3A.html
mp.ketengxin.com/blog/Lq2Km7Jx8B.html
mp.ketengxin.com/blog/Xt9Pm4Vc1C.html
mp.ketengxin.com/blog/Cd3Qv8Bn6D.html
mp.ketengxin.com/blog/Zx7Lp2Yr5E.html
mp.ketengxin.com/blog/Gm1Jd6Wv9F.html
mp.ketengxin.com/blog/Hv4Kq9Nx2G.html
mp.ketengxin.com/blog/Mp8Rm3Bc7H.html
mp.ketengxin.com/blog/Tq1Yv5Ld4J.html
mp.ketengxin.com/blog/Qx6Jm2Wt9K.html
mp.ketengxin.com/blog/Vc3Pq7Rn1L.html
mp.ketengxin.com/blog/Km9Ld4Bv6M.html
mp.ketengxin.com/blog/Bp2Xv8Yc3N.html
mp.ketengxin.com/blog/Nr5Qm1Jx7P.html
mp.ketengxin.com/blog/Lv8Kd3Wt2Q.html
mp.ketengxin.com/blog/Xm4Pq9Bc6R.html
mp.ketengxin.com/blog/Ct1Rv7Lx5S.html
mp.ketengxin.com/blog/Zp8Jm2Yd4T.html
mp.ketengxin.com/blog/Gq3Kv6Nx9U.html
mp.ketengxin.com/blog/Hm7Ld1Wc5V.html
mp.ketengxin.com/blog/Mv4Pq8Bt2W.html
mp.ketengxin.com/blog/Tr9Ym3Jx6X.html
mp.ketengxin.com/blog/Qc2Kv7Ld1Y.html
mp.ketengxin.com/blog/Vp6Rm4Nc8Z.html
mp.ketengxin.com/blog/Kx1Jd9Wv3A.html
mp.ketengxin.com/blog/Bm5Qq2Yt7B.html
mp.ketengxin.com/blog/Nc8Lm4Hx1C.html
mp.ketengxin.com/blog/Lv3Pq9Rd6D.html
mp.ketengxin.com/blog/Xt7Km2Bc5E.html锁一起封装在类内部。对外只暴露方法,不让外部直接操作类变量,实现逻辑隔离。class Counter:
_count = 0 # 约定私有类变量
lock = Lock()
@classmethod
def add(cls):
with cls.lock:
cls._count +=1
外部代码不能直接随意改_count(约定),所有修改走类方法。全局变量很难做到这种封装隔离。
6. 对比总结表
表格
| 维度 | 全局变量 | 类变量 |
|---|---|---|
| 隔离粒度 | 模块级别 | 类级别 |
| 同模块 / 同类内 | 完全共享,无隔离 | 同类实例之间共享,无隔离 |
| 不同分组隔离 | 需要手动维护多个变量,容易冲突 | 新建一个类就完成一组隔离,天然支持 |
| 同名冲突 | 同一模块不能同名,直接覆盖 | 不同类可以同名,互不干扰 |
| 封装能力 | 差,全模块裸暴露 | 好,可以搭配方法、锁封装内部状态 |
| 跨模块 / 跨类 | 不同模块全局变量隔离 | 不同类的类变量隔离 |
| 线程安全 | 隔离不解决并发竞态,写要加锁 | 隔离不解决并发竞态,写要加锁 |
7. 一句话总结
- 全局变量隔离是以模块为边界,模块内部毫无隔离,容易全局污染。
- 类变量隔离是以类为边界,多个类天然分开多组状态,封装性更好,适合多组独立共享数据。
如果你需要,我可以写代码演示:全局变量命名冲突 vs 不同类类变量同名互不干扰。