1.  
  2. 主页
  3.  / 
  4. Python基础到高级
  5.  / 
  6. 面向对象
  7.  / 
  8. 访问控制

访问控制

类的访问控制

私有变量

在Python中,双下划线开始,非双下划线结尾的,都是私有的,在类的外部是无法访问的

In [26]: class Door:
    ...:     def __init__(self, status):
    ...:         self.__status = status   # 定义一个私有的属性
    ...:     def open(self):
    ...:         self.__status = 'openning'
    ...:     def close(self):
    ...:         self.__status = 'closed'
    ...:     def status(self):
    ...:         return self.__status
    ...:     

In [27]: door = Door('closed')

In [28]: door.status()
Out[28]: 'closed'

In [29]: door.__status   # 当通过实例访问私有的属性,会抛出AttributeError的错误
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-29-d55234f04e7f> in <module>()
----> 1 door.__status

AttributeError: 'Door' object has no attribute '__status'

Python中的若是定义了私有的属性,那么就需要通过类中指定的方法来访问,不然访问到的就不是我们想要的结果

当我们使用实例对私有属性进行赋值的时候,其实就是给实例重新创建了一个属性,也证实了Python的一个惯例,赋值及创建

In [30]: door.__status = 'lanyulei'

In [31]: door.__status   # 给对象新创建了属性,并没有去修改类中的__status
Out[31]: 'lanyulei'

In [32]: door.__dict__   # 在__dict__中是存在__status的方法的,说明给实例创建了一个新的属性
Out[32]: {'_Door__status': 'closed', '__status': 'lanyulei'}

尽管使用door实例给__status赋值了,但是其实在类中的__status是没有变化的,受保护的

In [34]: door.status()   # 使用指定的方法,获取到的__status的值
Out[34]: 'closed'

私有方法

和私有变量是相同,双下划线开始,非双下划线结尾的方法,也是私有的方法

由此可以得出一个结论,所有双下划线开始,非双下划线结尾的成员都是私有成员

In [35]: class Door:
    ...:     def __set_name(self, number):   # 定义一个私有方法
    ...:         self.number = number
    ...:         

In [37]: door = Door()   

In [38]: door.__set_name(5001)   # 调用私有方法,报出了错误,无法调用
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-38-418365dabb86> in <module>()
----> 1 door.__set_name(5001)

AttributeError: 'Door' object has no attribute '__set_name'

在Python中是没有完全的私有属性的

当定义了私有成员的时候,其实只是修改了属性的名,因此当访问私有属性的时候,就会访问不到

Python将定义私有的属性的时候,将私有属性修改成了,_类名 + 私有属性名称

In [40]: class Door:
    ...:     def __init__(self, status):
    ...:         self.__status = status    # 定义了一个私有的属性
    ...:     def open(self):
    ...:         self.__status = 'openning'
    ...:     def close(self):
    ...:         self.__status = 'closed'
    ...:     def status(self):
    ...:         return self.__status
    ...:     
    ...:     

In [41]: door = Door('closed')

In [42]: door.__status    # 直接使用实例访问私有的属性,报出了AttributeError错误
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-42-d55234f04e7f> in <module>()
----> 1 door.__status

AttributeError: 'Door' object has no attribute '__status'

In [43]: door._Door__status   # 使用修改后的私有属性的名称
Out[43]: 'closed'

当创建了私有属性的时候,实例化类后,会在实例中的__dict__方法中追加修改后的私有变量keyword-only数据,因此我们可以从__dict__查看实例的属性

In [44]: door.__dict__    # 
Out[44]: {'_Door__status': 'closed'}

当然,如果想在外部强制的修改私有属性也是可以的

In [48]: door.status()   # 获取私有属性的值
Out[48]: 'closed'

In [49]: door._Door__status = 'openning'   # 在外部重新定义私有属性的值

In [50]: door.status()   # 验证结果,确定私有属性已经在外部修改
Out[50]: 'openning' 

这种方法可以修改私有属性的值,但是既然定义为私有属性了,就不能随意的可以更改,因此除非真的有必要,并且清楚明白的知道使用后会有什么后果,否则不用使用这个黑魔法

有一种使用单下划线 ‘_’ 的属性和方法,是一种惯用法,标记成员为私有成员,但是解释器不做任何处理

In [51]: class Door:
    ...:     def _set_name(self, number):   # 定义一个方法,单下划线的方法,就是标记说明这个是一个私有属性,但是程序不会错任何处理
    ...:         self.number = number

property装饰器

property装饰器会把一个仅有self参数的函数,变成一个变量,属性的值,就是方法的返回值

In [52]: class Door:
    ...:     def __init__(self, status):
    ...:         self.__status = status
    ...:     def open(self):
    ...:         self.__status = 'openning'
    ...:     def close(self):
    ...:         self.__status = 'closed'
    ...:     @property    # 装饰status方法
    ...:     def status(self):
    ...:         return self.__status
    ...:     
    ...:     

In [53]: door = Door('openning')

In [54]: door.status   # 使用访问属性的方式调用方法
Out[54]: 'openning'

In [55]: door.status()   # 直接调用方法,报出了TypeError的错误
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-55-76c604e52a9b> in <module>()
----> 1 door.status()

TypeError: 'str' object is not callable

property.setter装饰器可以通过两个方法将一个方法转化为属性对此赋值,但是对于需要装饰的方法也是有要求的:

  • 两个方法必须同名
  • 第二个方法必须接受两个参数self和value,value为所赋的值

给类中的私有属性__number进行判断赋值,number必须是整数,大于0,小于10000

In [9]: class Door:
   ...:     def __init__(self, number):
   ...:         self.__number = number
   ...:     @property
   ...:     def number(self):    # 返回属性被重新赋值后的结果集
   ...:         return self.__number 
   ...:     @number.setter    # 给number方法做逻辑处理的
   ...:     def number(self, number): 
   ...:         if isinstance(number, int) and number > 0 and number < 10000:
   ...:             self.__number = number
   ...:             

In [10]: door = Door(1001)

In [12]: door.number
Out[12]: 1001

In [13]: door.number = 1002

In [14]: door.number
Out[14]: 1002
这篇文章对您有用吗?

我们要如何帮助您?

发表评论

您的电子邮箱地址不会被公开。