Discuss / Python / 为什么给私有变量绑定属性不成功呢

为什么给私有变量绑定属性不成功呢

Topic source
class Student(object):
    def __init__(self,score):
        self.__score = score
     def get_score(self):
        return self.__score

 s = Student(90)

 def set_score(self,score):
     self.__score = score

 s.set_score = MethodType(set_score,s)
 s.set_score(59)
 print(s.get_score())

输出:90 为什么对于私有数据绑定了改变私有数据的方法可还是不能改变私有数据的值呢?为什么不是后来的59呢?

是啊 这个问题有点奇怪 我给Student类新添加set__score方法也不能对score进行修改。

对啊,为什么不行啊,谁知道啊解释一下

萌13131313

#5 Created at ... [Delete] [Delete and Lock User]
>>> class Student(object):
...     def __init__(self,score):
...         self.__score = score
...     def get_score(self):
...         return self.__score
...
>>> s = Student(90)
>>>
>>> def set_score(self,score):
...     self.__score = score
...
>>>
>>> dir(s)
['_Student__score', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_score']
>>> Student.set_score = set_score
>>> dir(s)
['_Student__score', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_score', 'set_score']
>>> s.set_score(59)
>>> dir(s)
['_Student__score', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__score', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_score', 'set_score']
>>> s._Student__score
90
>>> s.__score
59

萌13131313

#6 Created at ... [Delete] [Delete and Lock User]

更详细的解答:

伪私有属性是在创建类对象时就确定的:

创建一个A类并为其实例添加一个私有属性:

>>> class A:
...     def __init__(self):
...             self.__name = 10
...

创建实例并调用其属性:

>>> x = A()
>>> x.__name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__name'

属性变成了"_类名__属性名"的格式了:

>>> x._A__name
10

为什么会这样呢?事实上,创建类对象时,如果遇见有双下划线开头的变量,Python会自动替换为_Classattr格式,例如本例的name,在类内部已经替换成如下:

self._A__name

所以当你执行A()时,实际上Python运行的代码如下:

>>> class A:
...     def __init__(self):
...             self._A__name = 10
...

现在我们为A类手动添加一个方法:

def setname(self,name):
    self.__name = 20
A.setname = setname

当你运行setname时,setname中定义的__name属性的压根就不会替换成_Class__name的格式,为什么呢?因为替换操作只是在创建类对象时才进行的!

所以当你通过为实例执行setname时,是和直接为实例赋值一个双下划线开头的变量是一样的,替换根本就没有进行,只不过增加了一个新的变量而已:

>>> A.setname = setname
>>>
>>> x = A()
>>> x.setname(10)        #等于x.__name = 10
>>> x.__name
20
>>> x._A__name
10

xuziye2012

#7 Created at ... [Delete] [Delete and Lock User]

你这个就是解释器在解释时的问题。你可以选择以下两种代码,他们的效果是一样的,都能达到你的预期。

class Student(object):
    def __init__(self,score):
        self.__score = score
    def get_score(self):
        return self.__score    
from types import MethodType
s = Student(90)
def set_score(self,score):
    self._Student__score = score
s.set_score = MethodType(set_score,s)
s.set_score(59)
print(s.get_score())

OR

class Student(object):
    def set_score(self,score):
        self.__score = score            
from types import MethodType
s = Student(90)
s.set_score = MethodType(set_score,s)
s.set_score(59)
print(s.get_score())

你从外部修改class内部的开头的属性,需要特别注意,比如这里应该用 self._Studentscore

最爱臭屁k

#8 Created at ... [Delete] [Delete and Lock User]

回复“萌12313(那个皇阿玛头项的)”主要是因为你在类里创建的“name”是私有的,所以在实例中是没法直接调用私有对象的,只能通过“_classname.name”访问,若想用实例.方法直接调用的话,需要在类里declar一个 getname方法,就可以了,关于这个问题,廖老师早之前有很详细清楚的讲解。


  • 1

Reply