- 属性的访问权限: 公有属性、受保护的属性、私有属性
- Python中并没有真正的私有化支持, 但是可以使用下划线, 完成伪私有的效果
一、公有属性
- 公有属性
* 类内部访问* 子类内部访问* 模块内其他位置: 父类, 派生类, 父类实例, 派生类实例* 跨模块访问: import, from 模块 import *复制代码
1、类内部访问
class Animal: name = "旺财" def call(self): print(Animal.name) print(self.name)a = Animal()a.call()# 打印结果:旺财旺财复制代码
2、子类中访问
class Animal: name = "旺财" class Dog(Animal): def call(self): print(Dog.name) print(self.name)d = Dog()d.call()# 打印结果:旺财旺财复制代码
3、模块内其他位置访问
- 父类, 派生类
class Animal: name = "旺财" class Dog(Animal): pass print(Animal.name)print(Dog.name)# 打印结果:旺财旺财复制代码
- 父类实例, 派生类实例
class Animal: name = "旺财" class Dog(Animal): passa = Animal()d = Dog()print(a.name)print(d.name)# 打印结果:旺财旺财复制代码
4、跨模块访问类的属性
-
在其他模块中导入使用, 假设本模块名字为
Module
-
import 模块名
import Modulepirnt(Module.Animal.name) # 打印: 旺财复制代码
from 模块名 import *
from Python import *print(Animal.name) # 打印: 旺财复制代码
5、跨模块访问变量
- 在模块
Module
内定义一个变量
a = 10复制代码
import 模块名
: 跨模块访问Module
中的变量a
import Modulepirnt(Module.a) # 打印: 10复制代码
from 模块名 import *
: 跨模块访问Module
中的变量a
from Python import *print(a) # 打印: 10复制代码
二、受保护的属性
- 受保护的属性: 在定义属性时, 在名称前面加上一个下划线
_
* 类内部访问* 子类内部访问* 模块内其他位置: 父类, 派生类, 父类实例, 派生类实例, 但是会有警告* 跨模块访问: import 模块: 可以访问, 但是会有警告 from 模块 import *: 可以访问, 但是会有警告复制代码
1、类内部访问
- 正常访问, 没有警告
class Animal: _name = "富贵" def call(self): print(Animal._name) print(self._name)a = Animal()a.call()# 打印结果:富贵富贵复制代码
2、子类内部访问
- 正常访问, 没有警告
class Animal: _name = "富贵"class Dog(Animal): def call(self): print(Dog._name) print(self._name)d = Dog()d.call()# 打印结果:富贵富贵复制代码
3、模块内其他位置
- 父类、派生类访问, 会有警告
class Animal: _name = "富贵" class Dog(Animal): pass; print(Animal._name)print(Dog._name)# 打印结果:富贵富贵# 警告: Access to a protected member _name of a class复制代码
正常打印, 但是会发出警告: Access to a protected member _name of a class
- 父类实例、派生类实例访问, 会有警告
class Animal: _name = "富贵" class Dog(Animal): pass; a = Animal()d = Dog()print(a._name)print(d._name)# 打印结果:富贵富贵# 警告: Access to a protected member _name of a class复制代码
正常打印, 但是会发出警告: Access to a protected member _name of a class
4、跨模块访问类的属性
-
在其他模块中导入使用, 假设本模块名字为Module
-
import 模块名
: 可以访问, 但是会有警告
import Moduleprint(Module.Animal._name) # 打印: 10# 警告: Access to a protected member _name of a class复制代码
from 模块名 import *
: 可以访问, 但是会有警告
from Module import *print(Animal._name)# 警告: Access to a protected member _name of a class复制代码
5、跨模块访问变量
- 假设模块
Module
中有一个变量
_a = 10复制代码
import 模块名
: 可以访问, 但是会有警告
import Moduleprint(Module._a) # 打印: 10# 警告: Access to a protected member _a of a module复制代码
from 模块名 import *
: 不可以访问, 报错
from Module import *print(_a) # 报错: NameError: name '_a' is not defined复制代码
5、__all__
__all__
: 表示其他模块使用本模块式时, 可以导入的变量, 在默认情况下, 如果变量前有一个下划线_
, 例如:_a
, 就不会存放在__all__
中- 我们在
__all__
中加上_a
, 就可以在其他模块中使用_a
# Module模块__all__ = ["_a"]_a = 10复制代码
# 其他模块from Module import *print(_a) # 打印: 10复制代码
三、私有属性
- 私有属性: 只能在类的内部访问
* 类内部访问* 子类不能访问* 模块内其他位置不能访问* 跨模块不能访问复制代码
1、类内部访问
class Animal: __name = "狗蛋" def call(self): print(Animal.__name) print(self.__name)a = Animal()a.call()# 打印效果:狗蛋狗蛋复制代码
2、私有属性的实现机制
-
私有属性的实现机制 --
名字重整(Name Mangling)
-
解释器会将带有两个下划线
__
的属性的名字修改, 例如_类名__x
class Aminal: __name = "狗蛋"复制代码
- 可以通过类的
__dict__
属性, 查看类中的属性
print(Animal.__dict__)# 打印: {'__module__': '__main__', '_Animal__name': '狗蛋', '__dict__':, '__weakref__': , '__doc__': None}复制代码
- 可以看到有一个属性的名字叫
_Animal__name
, 我们可以直接在类的外面访问它
print(Animal._Animal__name) # 打印: 狗蛋复制代码
名字重整的目的: 防止外界直接访问, 防止被子类同名称属性覆盖
模块内带有两个下划线的变量与只有一个下划线的变量使用方法一致, 不再测试
3、私有属性一个简单的应用场景
- 定义一个
Person
类, 并在初始化方法中添加私有属性__age
class Person: def __init__(self): self.__age = 0复制代码
- 因为私有属性是不暴露给外界的, 所以在赋值和取值的时候, 需要定义两个方法
def setAge(self, value): self.__age = value def getAge(self): return self.__age复制代码
- 因为
__age
描述的是人的年龄, 所以必须是int
类型, 且在0-200
之间
def setAge(self, value): if isinstanse(value, int) and 0 < value < 200: self.__age = value复制代码
- 完整代码如下:
class Person: def __init__(self): self.__age = 0 def setAge(self, value): if isinstance(value, int) and 0 < value < 200: self.__age = value def getAge(self): return self.__age复制代码
- 在赋值和取值时, 直接调用方法就可以了
p = Person()p.setAge(20) # 赋值age = p.getAge() # 取值print(age) # 打印: 20复制代码
补充: 关于属性命名时加下划线的规范问题
- 在名字后面添加一个下划线, 用于与系统关键词区分, 例如:
class_
- 系统内键属性, 两端各加两个下划线, 例如:
__dict__
, 我们给变量命名时应该避免这种命名方式, 与系统区分开