Python类中双下划线私有属性为何能在外部赋值与访问

木白
木白
发布时间:2026-10-12| 3人浏览过
原创

本文解析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类中私有属性外部赋值与访问的讨论,即为小编分享的全部内容,希望能对大家有所帮助,也希望大家多多支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。