学习要点
在Python中,类的访问限制可以通过使用单下划线 _
和双下划线 __
进行控制,但这并不是严格的访问控制,而是一种命名约定。
-
单下划线
_
(约定性私有):- 一个下划线前缀表示一个属性或方法应该被视为“内部”使用。这只是一种约定,并没有严格的强制规则。其他程序员应该将以一个下划线开头的属性或方法视为“内部”实现,不建议直接访问。
- 示例:
class MyClass: def __init__(self): self._internal_variable = 42 def _internal_method(self): print("This is an internal method.")
-
双下划线
__
(名称改写):-
一个双下划线前缀将属性或方法“名称改写”(name mangling)。Python会在名称前面加上一个下划线和类名,以避免子类意外地重写父类的属性或方法。
-
示例:
class MyClass: def __init__(self): self.__private_variable = 42 def __private_method(self): print("This is a private method.")
-
请注意,这种机制并不是严格的访问控制,而是一种名称改写,可以通过特定的方式来访问:
obj = MyClass() print(obj._MyClass__private_variable) # 访问双下划线属性 obj._MyClass__private_method() # 访问双下划线方法
-
需要注意的是,这些只是一种约定,Python 并没有严格的访问控制机制。尽管可以通过这些方式来阻止直接访问属性和方法,但在实践中,程序员们通常会遵循一种“不要破坏私有性”的原则,而是信任其他程序员遵循良好的编程实践。
学习测试代码
"""
# -*- coding: utf-8 -*-
# @Time : 2023/9/20 15:25
# @Author : 王摇摆
# @FileName: test1.py
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_44943389?type=blog
"""
# 计算学生的成绩,并得到学生的评级
# 希望内部属性不被外部访问和更改,对私有变量作出调整
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def evaluate(self) -> str:
"""
@rtype: str
"""
if self.__score >= 90:
result = 'A'
elif self.__score >= 80:
result = 'B'
else:
result = 'C'
return 'The student is {},his evaluate is {result_final}'.format(self.__name, result_final=result)
def print_score(self):
string = f'The student is {self.__name},his score is {self.__score}'
print(string)
# 留出私有属性的公有访问方法
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_name(self, name):
self.__name = name
# 最基本的seter方法
def set_score(self, score: int):
self.__score = score
# 高阶的setter方法,可以对传入的参数进行检查
def set_score_advanced(self, score: int):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('Sry,bad input...,Please input again.')
if __name__ == '__main__':
wangguowei1 = Student('王国炜1', 100)
wangguowei2 = Student('王国炜2', 85)
wangguowei3 = Student('王国炜3', 60)
wangguowei1.print_score()
wangguowei2.print_score()
wangguowei3.print_score()
print()
print(wangguowei1.evaluate())
print(wangguowei2.evaluate())
print(wangguowei3.evaluate(), end='')
# 在这里测试getter和setter方法对实例进行更改
print()
print(wangguowei1.get_name(), wangguowei1.get_score())
# wangguowei1.set_score_advanced(110) # 报错不就对了嘛!
print()
# 使用特殊方法强制修改私有变量
wangguowei1._Student__name = 'wangyaobai'
print(wangguowei1.get_name())
print(wangguowei1._Student__name)
# 一种错误的写法
wangguowei1.__name = "fake name"
# 看似给类中添加了一个新的变量,但是和类中的属性不是一回事,因为类中本身的属性已被解释器自动翻译成了_Student__name
print(wangguowei1.__name)
print(wangguowei1.get_name())
print(wangguowei1.__name == wangguowei1.get_name())
运行结果
D:\ANACONDA\envs\pytorch\python.exe C:/Users/Administrator/Desktop/Code/Learn_Pyhon3.7/liaoxuefeng/oop/test1.py
The student is 王国炜1,his score is 100
The student is 王国炜2,his score is 85
The student is 王国炜3,his score is 60
The student is 王国炜1,his evaluate is A
The student is 王国炜2,his evaluate is B
The student is 王国炜3,his evaluate is C
王国炜1 100
wangyaobai
wangyaobai
fake name
wangyaobai
False
Process finished with exit code 0
千万要注意的细节问题
- 弱私有的属性成员,还是能通过实例直接进行修改
- 强私有的属性成员,不能通过实例进行修改
看似修改成功,但是和实际内存中定义的属性不是一回事
练习代码
"""
# -*- coding: utf-8 -*-
# @Time : 2023/9/20 16:49
# @Author : 王摇摆
# @FileName: practice1.py
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_44943389?type=blog
"""
"""
请把下面的Student对象的gender字段对外隐藏起来,用get_gender()和set_gender()代替,并检查参数有效性:
"""
class Student(object):
def __init__(self, name, gender):
self.__name = name
self.gender = gender
self.hobby = 'pingpang'
def get_gender(self):
return self.gender
def set_gender(self, param:str):
self.gender = param
def set_name(self, name):
self.__name = name
def get_name(self, ):
return self.__name
print(1)
if __name__ == '__main__':
# 在正式运行测试代码之前的准备工作
bart = Student('Bart', 'male')
print(bart.get_name())
print(bart.hobby)
print()
# 1. 强弱私有属性的测试
bart.__name = 'wangguowei'
print(bart.__name) # 实例私有属性的名字已被解释器转为其他,这里顶多算是定义一个临时共有属性
print(bart.get_name())
bart.hobby = 'cf'
print(bart.hobby)
# 2. 直接给实例添加临时内容
bart.university = 'NUC'
print(bart.university)
# 3. 作业内容
print()
bart.set_name("Bart")
if bart.get_gender() != 'male':
print('测试失败!')
else:
bart.set_gender('female')
if bart.get_gender() != 'female':
print('测试失败!')
else:
print('测试成功!')
print(100)