Python类的私有化属性与私有方法使用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Python类的私有化属性与私有⽅法使⽤
Python默认的成员⽅法和成员属性都是公开的,没有类似Java的public,private,protected等关键词来修饰。
在python中定义私有变量只需要在变量名或函数名前加上
"__"两个下划线,那么这个函数或变量就变成私有(⽅法也是⼀样,⽅法名前⾯加了2个下划线的话表⽰该⽅法是私有的,否则为公有的)。
1. 类的变量类型
xx: 函数外为公有变量,函数内为局部变量
_x: 单前置下划线,protected类型的变量,不能⽤于’from module import *,即保护类型只能允许其本⾝与⼦类进⾏访问。
并未完全私有,只是表明不希望⽤户直接访问属性,实际上,实例._变量,
可以被访问。
_xx:双前置下划线,private类型的私有变量,⽆法在外部直接访问(名字重写所以访问不到),但可以在类内部使⽤私有⽅法。
本质是因为 python 编译器做了⼀次名称变换,
xx: 双前后下划线,⽤户名字空间的魔法对象或属性。
例如:__init__、__new__ , __ 不要⾃⼰发明这样的名字
xx: 单后置下划线,⽤于避免与Python关键词的冲突
2. 引⼊私有化场景
属性赋值⽅法:在绑定属性时,如果我们直接把属性暴露出去,会出现属性随便更改的情况。
police = Role('Alex', 'police', 'AK47') # 实例化⼀个游戏⼈物
police.life_value = 0 # ⽣命值置为0
上⾯的情况很明显不符合实际,我们实例化出来的游戏对象还没开始,直接通过外部⽅法把⽣命值置为0,接下来game over!很明显是作弊,因此我们引⼊私有化的概念,⽆论是属性还是⽅法,在
定义前加双下划线__,就可使得属性或⽅法只能在类内部通过某些特定的场景调⽤。
在下⾯的代码中,访问police.__life_value会提⽰"AttributeError: 'Role' object has no attribute '__life_value"。
class Role(object):
def__init__(self, name, role, weapon, life_value=100, money=15000):
= name
self._role = role # 这是⼀个protected类型的属性
self.weapon = weapon
self.__life_value = life_value # 这是⼀个私有类型的属性
self.money = money
def__shot(self):
# 开了枪后要减⼦弹数
print("shooting...")
def got_shot(self):
# 中枪后要减⾎
self.__life_value -= 10
print(f"ah...,I got shot...,剩余⽣命值为{self.__life_value}")
def buy_gun(self, gun_name, gun_money):
# 检查钱够不够,买了枪后要扣钱
if self.money > gun_money:
self.money -= gun_money
print("just bought %s" % gun_name)
else:
print("余额不⾜,⽆法⽀付买枪费⽤")
police = Role('Alex', 'police', 'AK47') # ⽣成⼀个⾓⾊
print(police.__life_value)
⽆法检查参数范围:设置的属性不符合实际。
直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改。
zhangsan = Student("DY","100")
zhangsan.score = 99999
实际开发中为了程序的安全,关于类的属性都会封装起来,Python中为了更好的保存属性安全,不能随意修改。
⼀般属性的处理⽅式为:
①将属性定义为私有属性。
②提供⼀个setter或getter⽅法
为了限制score的范围,可以通过⼀个set_score()⽅法来设置成绩,再通过⼀个get_score()来获取成绩,这样,在set_score()⽅法⾥,就可以检查参数:
class Student(object):
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
def get_score(self):
return self._score
if__name__ == '__main__':
s = Student()
私有化的使⽤场景:
1. 属性不允许在外部做更改
2. ⽅法在某种特定场景下才可以执⾏
3. 检查参数范围:外部设置超出范围时校验
3. 私有化封装底层实现原理
__shot⽅法加上双下划线后为什么对象外部访问提⽰“AttributeError: 'Role' object has no attribute '__shot'”。
事实上,对于以双下划线开头命名的类属性或类⽅法,Python 在底层实现时,将它们的名称都偷偷改成了 "_类名__属性(⽅法)名" 的格式。
所以__shot重写为:_Role__shot。
也因此访问原来的⽅法名会提⽰类没有__shot属性,⼈家已经改名字了,当然访问不到了。
# 使⽤ dir函数看看实例对象police⾥⾯有哪些内容,如下图所⽰:
['_Role__life_value', '_Role__shot', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__ #或可使⽤第⼆种⽅法
import inspect
# 使⽤inspect检查现场对象
methods = inspect.getmembers(police, predicate=inspect.ismethod)
print(methods)
执⾏结果:
[('_Role__shot', <bound method Role.__shot of <__main__.Role object at 0x000001D3F6FFCE48>>), ('__init__', <bound method Role.__init__ of <__main__.Role object at 0x000001D3F6FFCE48>>), ('buy_gun'私有化属性或⽅法有⽅式可以访问吗?
4. 访问私有化属性/⽅法
上⾯有说属性前加双下划线⽆法访问的原因,是因为在Python编译器重写变量名/⽅法名,所以导致访问不到。
在规范上,这种双下划线的私有⽅法和私有属性是不应该在外部访问的,但是如果就是想强⾏访问还是有⽅法的:直接访问重写名称后的属性名或⽅法名。
police._Role__shot() # 强⾏调⽤私有⽅法
print(police._Role__life_value) # 强⾏调⽤私有属性执⾏结果:
shooting...
100。