1小时搞懂Python类的访问控制!

292 阅读3分钟

一、访问控制的本质:数据安全与接口设计

1.1 类属性和方法的访问控制

一般情况下,我们会使用 __private_attrs 两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrsPython作为动态语言,打破了传统OOP语言对访问控制的刚性限制。同理类方法的访问控制与属性一样。

class Student:
    def __init__(self, score, name):
        self.name = name  # 公有属性, 可以直接被访问
        self.__score = score  # 私有属性, 不能被直接访问,但是可以通过双下划线实现Name Mangling访问

    def get_score(self):  # 公有方法, 可以直接被访问
        return self.__score

    def __get_score(self):  # 私有方法, 不能被直接访问,但是可以通过双下划线实现Name Mangling访问
        return self.__score
        
s = Student(100, 'Bob')
print(s.name)  # 访问公有属性
print(s._Student__score)  # 访问私有属性,Name Mangling
print(s.get_score())  # 访问公有方法
print(s._Student__get_score())  # 访问私有方法,Name Mangling

这段代码看似实现了信息隐藏,实际通过_Student__score仍可访问。这种"约定优于限制"的设计哲学,体现了Pythonic的核心思想。

1.2 类专有的方法

方法说明
__init__构造函数,在生成对象时调用
__del__析构函数,释放对象时使用
__repr__打印,转换
__setitem__按照索引赋值
__getitem__按照索引获取值
__len__获得长度
__cmp__比较运算
__call__函数调用
__add__加运算
__sub__减运算
__mul__乘运算
__div__除运算
__mod__求余运算
__pow__乘方

当然有些时候我们需要获取类的相关信息,我们可以使用如下的方法:

  • type(obj):来获取对象的相应类型;
  • isinstance(obj, type):判断对象是否为指定的 type 类型的实例;
  • hasattr(obj, attr):判断对象是否具有指定属性/方法;
  • getattr(obj, attr[, default]) 获取属性/方法的值, 要是没有对应的属性则返回 default 值(前提是设置了 default),否则会抛出 AttributeError 异常;
  • setattr(obj, attr, value):设定该属性/方法的值,类似于 obj.attr=value;
  • dir(obj):可以获取相应对象的所有属性和方法名的列表

二、访问器模式的现代写法(@property进阶)

传统getter/setter模式:

class TemperatureSensor:
    def get_temperature(self):
        return self._raw_data * 0.8 - 5
    
    def set_temperature(self, value):
        if value < -273.15:
            raise ValueError("Absolute zero violation")
        self._raw_data = (value + 5)/0.8

sensor = TemperatureSensor()
sensor.set_temperature(20)
print(sensor.get_temperature())

现代Python推荐使用更优雅的@property装饰器:

class TemperatureSensor:
    @property
    def temperature(self):
        return self._raw_data * 0.8 - 5
    
    @temperature.setter
    def temperature(self, value):
        if value < -273.15:
            raise ValueError("Invalid temperature")
        self._raw_data = (value + 5)/0.8


sensor = TemperatureSensor()
sensor.temperature = 25
print(sensor.temperature)

实战技巧:在setter中可以加入类型检查、范围验证、历史记录等增强功能

三、总结

控制级别定义方式可访问范围使用场景
公有成员name任意位置对外暴露的完整接口
保护成员_name (单下划线)本类及子类内部实现但允许继承扩展
私有成员__name本类内部绝对私有防止外部干扰

如果你喜欢这篇文章,欢迎点赞、收藏和转发,更多Python干货内容敬请关注!