繁体   English   中英

如果一个属性被初始化为 public 但 setter 和 getter 将其视为受保护的,是否受保护?

[英]Is an attribute protected if initialized as public but setters & getters treat it as protected?

在学习 Python 中面向对象编程的基础知识时,我遇到了一些我无法有效搜索以找到匹配关键字的问题:

我为一个基础类Course编写了验证检查,它有一个受保护的属性_level getter 和 setter 将其视为受保护的属性。 验证确保self._level在 0 到 100 之间。

  • 但是 setter 中的验证检查被规避了:
class Course:
    
    def __init__(self, level=None):        
        self._level = level if level else 0
        
    @property
    def level(self):
        return self._level
    
    @level.setter
    def level(self, value):        
        if not isinstance(value, int):
            raise TypeError('The value of level must be of type int.')        
        if value < 0:
            self._level = 0
        elif value > 100:
            self._level = 100
        else:
            self._level = value

###
courses = [Course(), Course(10), Course(-10), Course(150)]
for c in courses:
    print(c.level)
>>> 0
>>> 10
>>> -10
>>> 150
  • 然后我将初始化从受保护的self._level更改为公共属性self.level 我的 setter 和 getter 仍然引用受保护的属性self._level
class Course:
    
    def __init__(self, level=None):        
        self.level = level if level else 0
        
    @property
    def level(self):
        return self._level
    
    @level.setter
    def level(self, value):        
        if not isinstance(value, int):
            raise TypeError('The value of level must be of type int.')        
        if value < 0:
            self._level = 0
        elif value > 100:
            self._level = 100
        else:
            self._level = value
        
courses = [Course(), Course(10), Course(-10), Course(150)]
for c in courses:
    print(c.level)
>>> 0
>>> 10
>>> 0
>>> 100

令我惊讶的是,这个类不仅意识到它是相同的属性,而且现在我的验证已经实现了!

Python 如何协调self.levelself._level ,为什么我必须将其初始化为公共属性才能启动验证?

问题是你没有在__init__中使用你的property ,所以当然,永远不会调用属性设置器!

self._level = level if level else 0

应该:

self.level = level if level else 0

一些建议,不要再用“受保护”与“公共”来思考了 Python 运行时无法识别这样的东西Python 中没有访问修饰符 这些仅仅是命名约定 我认为这个命名约定让你感到困惑。 没有理由如果你有

@property
def level(self):
    ...

应该修改一个名为_level的变量,同样,这只是一个约定。 你可以随心所欲地称呼它。 因此,请考虑以下事项:

class Course:

    def __init__(self, level=None):        
        self.foo = level if level else 0
        
    @property
    def level(self):
        return self.foo
    
    @level.setter
    def level(self, value):        
        if not isinstance(value, int):
            raise TypeError('The value of level must be of type int.')        
        if value < 0:
            self.foo = 0
        elif value > 100:
            self.foo = 100
        else:
            self.foo = value

这应该会让你更清楚为什么你的__init__从来没有真正调用过 setter——因为你没有使用这个属性! 该属性是level ,而不是foo 当然,您可能永远不会使用像上面这样的命名方案,因为它会造成混淆,但它应该可以说明您的代码发生了什么

现在,为什么我们将__init__更改为:

    def __init__(self, level=None):        
        self.level = level if level else 0

该属性被调用。 因为self.level是属性,而不是self.foo 属性 setters/getters 只会在你使用 self.level 而不是 self.foo 的属性self.level self.foo

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM