Python中关于Class私有变量的一个小问题

如果 Python 中的内部属性不希望被外部访问,那么就应该在属性名称前加两个下划线。这样,就无法在外部直接访问了。如下:

class Student(object):
def __init__(self, score):
    self.__score = score

之后,我们如果直接想通过属性名称调用,就需要使用[@property](/user/property)了:

[@property](/user/property)
def score(self):
        return self._score

如果这样,要增加不少代码,而调用实例名称.score的结果与不加下划线的结果一致。那么,加两个下划线的目的是什么呢


Python中关于Class私有变量的一个小问题

11 回复

加下划线就是为了让变量 private, 然而你又想在外部访问 private 变量。这让大家很为难呐🤷‍♂️


我无法理解你的问题

加下划线一般意味着这个变量是私有的,也就是希望你不要去修改它。
但是,你只加下划线的话,虽然无法直接访问,但是你想的话还是可以访问并修改的!(也就是说,下划线只是一个大家的一个共识,它只对 responsible user 起作用)
但你加上第二段代码后,它内部通过__setattr__方法会拦截你对这个私有变量的修改。也就是从代码层面防止你动手脚了。
这就是两者区别,相当于一个道德约束,一个是法律约束

不能修改

setattr__并没有阻止对_score 的访问,而是模拟了对 score 的访问,尽管它并不存在

加一个下划线是约定,也就是外部的代码不应该去访问_score ;加两个下划线是强制,外部的代码不能去访问__score (尽管根据混淆规则还是有办法去访问,但是更不直观)

回到问题,加两个下划线的目的是防止外部代码去访问__score,任何对它的读写应该通过成员函数来完成。好处是读写的时候你可以做更多的判断,例如写的时候判断分数是不是在一个范围内,读的时候做校验之类的。而 property 利用 Python 的机制(也就是上面说的__setattr
)实现了更直观的语法,你可以通过 print self.score 来调用 self.score()函数,而它正巧返回了 self.__score 这个成员变量。

纠错…上面说的 Python 机制并不是__setattr__,而是 property 对象的__get__

#2 set 的作用不应该是拦截,而是类似于装饰器一样的,对传入的值做一些过滤,类型验证是否合法等工作,没问题就放行。

嗯。。我错了 内部实现机制是 Descriptor (我一开始以为是用__getattribute__,__setattribute__来实现的… ,但是这样会影响到其他属性访问)

我贴一下我现在的理解,你们看对不,不对望指正:

score = property(fget, fset, fdel, docs),会生成一个名为 score 的 Descriptor.这样,当我们访问
Student.score 等于 Student.score.get 。而 get 内部调用了函数 fget。

至于
<br><br>def score(self):<br> return self._score<br>.setter<br>def score(self):<br> pass<br>
则是分别调用了 property 的 getter、setter 将对应的函数引用赋值给 fget 和 fset

1、外部实例对象想访问对象成员变量应该是通过 getsatt 方式获取属性
2、楼主使用 修饰 score 函数使其成为属性
3、在外部调用的时候会经历 1、2 两个步骤
4、两个下划线就是私有变量,希望你不要从外部访问,但是你仍然是可以从外部通过某个手段访问,楼主可以试试,没有绝对的私有,只是你这么定义就是遵守约定不要乱来

打错了,getattr

回到顶部