Python类中双下划线私有属性为何能在外部赋值与访问
本文解析Python中双下划线私有属性的访问机制。指出外部通过__attr赋值实则是创建实例动态属性,未改变类真正的私有属性。通过名称修饰规则,解释__attr与_classname__attr的区别,以及直接访问未赋值私有属性触发AttributeError的原因。
Python类中双下划线私有属性为何能在外部赋值与访问
问题背景
在慕课网学习Python类的私有属性章节时,注意到一位学员提出的疑问:
将变量名改为__count后,为何实例变量在外部仍可修改__count?此处执行print p1.__count能够输出100。
class Person(object):
__count = 0
def __init__(self, name):
Person.__count = Person.__count + 1
self.name = name
print Person.__count
p1 = Person('Bob')
p1.__count=100
print p1.__count
p2 = Person('Alice')
print Person.__count
解决方案:
核心结论:
对p1.__count进行赋值的操作,实际上是在p1实例中定义了一个名为__count的新变量(鉴于Python中变量均为动态特性),这并未改变类内部真正的属性定义。
详细解析版:
关键知识点:
1、类的“伪私有属性”机制 2、在类外部动态创建类属性
解决过程分析:
1、“伪私有属性”的概念解析:
Python类中通过双下划线前缀设置的“私有属性”实为“伪私有属性”。其原理在于Python编译器会自动将带有双下划线的“属性名”转换为“类名_属性名”的形式。因此,当我们在外部尝试使用原始“属性名”访问私有属性时,会触发AttributeError异常,从而表现出“私有”的特性。然而,通过转换后的“类名_属性名”依然可以访问这些属性。
参考资源:http://www.pythonclub.org/python-class/private
2、编写测试代码验证:
以下代码基于该学员提供的代码进行了修改以进行测试:
class Person(object):
#设置类属性
__count_of_class = 'original count_of_class'
def __init__(self, name):
self.name = name
print('in class Person : count_of_class = ', Person.__count_of_class,'\n')
#初始化实例p1
p1 = Person('Bob')
#在实例p1上修改属性值
p1.__count_of_class='I\'m not the original count_of_class!'
print('p1\'s _Person__count_of_class = ',p1._Person__count_of_class)
print('p1\'s __count_of_class = ',p1.__count_of_class,'\n')
#在类Person上修改属性值
Person.__count_of_class = 'I\'m not the original count_of_class!'
#将这句注释取消掉,会发现真正的私有属性的值也改变了
#Person._Person__count_of_class = 'I\'m not the original count_of_class!'
print('Person\'s _Person__count_of_class = ',Person._Person__count_of_class)
print('Person\'s __count_of_class = ',Person.__count_of_class)
分别在实例p1和类Person上进行操作,并分别打印“__属性名”以及“_类名__属性名”的结果。
输出结果如下:
in class Person : count_of_class = original count_of_class p1's _Person__count_of_class = original count_of_class p1's __count_of_class = I'm not the original count_of_class! Person's _Person__count_of_class = original count_of_class Person's __count_of_class = I'm not the original count_of_class!
**由此可见,虽然通过p1.__count_of_class进行了赋值,但类中真正的属性_Person__count_of_class的原始值并未发生改变。**
**然而,如果直接对p1._Person__count_of_class进行赋值,则会真正覆盖类属性定义的原始值。**
""" 取消掉 ##Person._Person__count_of_class = 'I\'m not the original count_of_class!' 的注释,输出结果: """ in class Person : count_of_class = original count_of_class p1's _Person__count_of_class = original count_of_class p1's __count_of_class = I'm not the original count_of_class! #注意这一句: Person's _Person__count_of_class = I'm not the original count_of_class! Person's __count_of_class = I'm not the original count_of_class!
由此可知:_count_of_class和_Person__count_of_class并非同一个对象。
后续疑问
那么,如果不先对p1.__count_of_class进行赋值,而是直接打印它,为何会触发AttributeError?
这是因为对p1.__count_of_class进行赋值的操作,本质上是在p1实例中定义了一个名为__count_of_class的变量(由于Python中所有变量均为动态类型)。
以下实例展示了如何通过外部赋值来为类创建属性:
class Person(object): pass p1=Person() #给p1创建属性new_of_instance p1.new_of_instance = 'I\'m new in p1!' print(p1.new_of_instance) #给Person类创建属性new_of_class Person.new_of_class = 'I\'m new in Person!' #在类中新加的属性,可以通过实例来访问 print(p1.new_of_class) >>>输出: I'm new in p1! I'm new in Person!
问题解决完毕。
以上关于Python类中私有属性外部赋值与访问的讨论,即为小编分享的全部内容,希望能对大家有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









