3.类的访问控制
目录:
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.通过访问控制,暴露适当的数据和操作给用户,该隐藏的隐藏起来,例如保护成员或私有成员。