PYTHON进阶

3.类的访问控制

2020-12-31  本文已影响0人  Stone_説

目录:
1.私有(private)属性
2.保护变量
3.私有方法
4.属性装饰器
5.封装概念

1.私有(private)属性

eg:

>>> class Person:
...     def __init__(self,name,age=18):
...             self.name = name
...             self.age = age
...     def growup(self,i=1):
...             if i > 0 and i < 150:
...                     self.age += i
>>> p1 = Person('tom')
>>> p1.growup(20)
>>> p1
<__main__.Person object at 0x7efd9fa3e430>
>>> p1.name
'tom'
>>> p1.age
38
>>> p1.age = 170
>>> p1.age
170

本来是想通过方法控制属性,但是由于属性在外部可以访问,则可以直接修改,因此,Python提供了私有属性可以解决这个问题。
私有属性:以双下划线开头的属性名,就是私有属性

>>> class Person:
...     def __init__(self,name,age=18):
...             self.name = name
...             self.age = age
...     def growup(self,i=1):
...             if i > 0 and i < 150:
...                     self.__age += i
>>> p1 = Person('tom')
>>> p1.growup(20)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in growup
AttributeError: 'Person' object has no attribute '_Person__age'
>>> p1.__age
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__age'

可以很明确的看到,外部已经访问不到__age了,可以通过内部方法进行访问。

>>> class Person:
...     def __init__(self,name,age=18):
...             self.name = name
...             self.__age = age
...     def growup(self,i=1):
...             if i > 0 and i < 150:
...                     self.__age += i
...     def getage(self):
...             return self.__age
>>> tom = Person('tom')
>>> tom.getage()
18

>>> tom.growup(20)
>>> tom.__age
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__age'
>>> tom.__age = 100
>>> tom.__age
100
>>> tom.getage()
38
>>> p1.__dict__
{'name': 'tom', 'age': 18}
>>> tom.__dict__
{'name': 'tom', '_Person__age': 38, '__age': 100}

NOTE:类定义的时候,如果声明一个实例变量的时候,使用双下划线,Python解释器会将其改名,转换名称为_类名__变量名的名称,所以原来的名字访问不到

>>> tom._Person__age = 50
>>> tom.getage()
50
>>> tom.__dict__
{'name': 'tom', '_Person__age': 50, '__age': 100}

知道了私有变量的新名称,就可以直接从外部访问到,并可以修改它

2.保护变量

在变量名前使用一个下划线,称为保护变量

>>> class Person:
...     def __init__(self,name,age=18):
...             self.name = name
...             self._age = age
>>> tom = Person('Tom')
>>> tom._age
18
>>> tom.__dict__
{'name': 'Tom', '_age': 18}

私有变量仅仅是一个约定,和普通变量属性一样,只是遇见时,不要直接使用

3.私有方法

>>> class Person:
...     def __init__(self,name,age=18):
...             self.name = name
...             self._age = age
...     def _getname(self):
...             return self.name
...     def __getage(self):
...             return self._age
... 
>>> tom = Person('Tom')
>>> tom._getname()
'Tom'
>>> tom.__getage()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__getage'
>>> tom.__dict__
{'name': 'Tom', '_age': 18}
>>> tom.__class__.__dict__
{
'__module__': '__main__', 
'__init__': <function Person.__init__ at 0x7fd9a378c8b0>, 
'_getname': <function Person._getname at 0x7fd9a378c940>, 
'_Person__getage': <function Person.__getage at 0x7fd9a378c9d0>, 
'__dict__': <attribute '__dict__' of 'Person' objects>, 
'__weakref__': <attribute '__weakref__' of 'Person' objects>, 
'__doc__': None
}
>>> tom._Person__getage()
18

单下划线的方法只是pyhtoner之间的约定,解释器并不做任何改变
双下划线的方法,是私有方法,解释器会改名,改名策略和私有变量相同,_类名__方法名
方法变量都在类的dict中可以看到

4.属性装饰器

一般会把实例的某些属性保护起来,不让外部直接访问,外部使用getter读取属性和setter方法设置属性

>>> class Person:
...     def __init__(self,name,age=18):
...             self.name = name
...             self.__age = age
...     def age(self):
...             return self.__age
...     def set_age(self,age):
...             self.__age = age
>>> tom = Person('Tom')
>>> tom.age()
18
>>> tom.set_age(34)
>>> tom.age()
34

property装饰器

>>> class Person:
...     def __init__(self,name,age=18):
...             self.name = name
...             self.__age = age
...     @property
...     def age(self):
...             return self.__age
...     @age.setter
...     def age(self,age):
...             self.__age = age
...     @age.deleter
...     def age(self):
...             print('del')
... 
>>> tom = Person('Tom')
>>> print(tom.age)
18
>>> tom.age = 20
>>> print(tom.age)
20

NOTE:使用perperty装饰器的时候这三个方法同名
1.property装饰器
后面跟的函数名就是以后的属性名,它就是getter。这个必须有,有了它至少是只读属性。

2.setter装饰器
与属性名同名,且接收2个参数,第一个是self,第二个是将要赋值的值,有了它属性可写。

3.deleter装饰器
可以控制是否删除属性,很少用

4.property装饰器必须在前,setter、deleter装饰器在后。property装饰器能通过简单的方式,把对方法的操作变成对属性的访问,并起到了一定隐藏效果。
变式1:

>>> class Person:
...     def __init__(self,name,age = 18):
...             self.name = name
...             self.__age = age
...     def getage(self):
...             return self.__age
...     def setage(self,age):
...             self.__age = age
...     def delage(self):
...             del self.__age 
...             print('del')
...     age = property(getage,setage,delage,'age property')
>>> tom = Person('Tom')
>>> print(tom.age)
18
>>> tom.age = 30
>>> print(tom.age)
30
>>> del tom.age
del
>>> print(tom.age)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in getage
AttributeError: 'Person' object has no attribute '_Person__age'

变式2:

>>> class Person:
...     def __init__(self,name,age=18):
...             self.name = name
...             self.__age = age
...     age = property(lambda self:self.__age)
>>> tom = Person('Tom')
>>> print(tom.age)
18

5.封装概念

Eccapsulation

1.将数据和操作组织到类中,即属性和方法
2.将数据隐藏起来,给使用者提供操作,使用者通过操作就可以获取或者修改数据。getter和setter。
3.通过访问控制,暴露适当的数据和操作给用户,该隐藏的隐藏起来,例如保护成员或私有成员。
上一篇下一篇

猜你喜欢

热点阅读