子类继承的类方法访问私有类变量的问题
子类继承的类方法访问私有类变量的问题
我完全懂你的困惑,咱们先拆解一下为什么会出现这个结果,再一步步解决问题。
首先得搞清楚Python里双下划线私有变量的机制:Python会对以双下划线开头的变量做「名字修饰(name mangling)」——简单说就是解释器会自动把__x改成_类名__x的形式。所以你代码里:
- 父类
Foo的__x实际会变成_Foo__x - 子类
Goo的__x实际会变成_Goo__x
而你在父类Foo里写的get_x方法,return cls.__x经过名字修饰后,其实是在找_Foo__x。哪怕你用子类Goo的实例调用这个方法,它本质还是父类的方法,只会去拿_Foo__x的值(也就是1),这就是为什么g.get_x()返回1。而y是公共变量,子类的y会直接覆盖父类的,所以get_y能拿到4。
接下来给你几个可行的解决方案,按推荐程度排序:
方案一:改用单下划线的「保护变量」(最推荐)
这是Python社区约定俗成的写法:单下划线开头的变量表示「仅供内部使用」,不会被名字修饰,子类可以正常覆盖。修改代码如下:
class Foo: _x = 1 y = 2 @classmethod def get_x(cls): return cls._x @classmethod def get_y(cls): return cls.y class Goo(Foo): _x = 3 y = 4 g = Goo() print("x=%d" % g.get_x()) # 输出 x=3 print("y=%d" % g.get_y()) # 输出 y=4
这种方法既符合Python编码规范,又能轻松实现子类覆盖父类变量的需求,是最优解。
方案二:在子类中重写get_x方法
如果你一定要保留双下划线的私有变量,可以在子类里重写get_x方法,让它返回子类自己的私有变量:
class Foo: __x = 1 y = 2 @classmethod def get_x(cls): return cls.__x @classmethod def get_y(cls): return cls.y class Goo(Foo): __x = 3 y = 4 @classmethod def get_x(cls): return cls.__x g = Goo() print("x=%d" % g.get_x()) # 输出 x=3 print("y=%d" % g.get_y()) # 输出 y=4
不过这种方法有点冗余,每个子类都得重写一遍get_x,适合特殊场景下使用。
方案三:利用名字修饰规则手动获取(不推荐)
你也可以通过getattr结合类名,手动拼接出修饰后的变量名来获取值,但这种方法破坏了私有变量的封装性,可读性也差,不建议使用:
class Foo: __x = 1 y = 2 @classmethod def get_x(cls): # 手动拼接修饰后的变量名 return getattr(cls, f"_{cls.__name__}__x") @classmethod def get_y(cls): return cls.y class Goo(Foo): __x = 3 y = 4 g = Goo() print("x=%d" % g.get_x()) # 输出 x=3 print("y=%d" % g.get_y()) # 输出 y=4
总结一下,优先选方案一,既简洁又符合规范。
备注:内容来源于stack exchange,提问作者AS Han
相关产品推荐
相关产品推荐

