美文网首页PYTHON进阶
3.类的访问控制

3.类的访问控制

作者: Stone_説 | 来源:发表于2020-12-31 21:36 被阅读0次

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

    相关文章

      网友评论

        本文标题:3.类的访问控制

        本文链接:https://www.haomeiwen.com/subject/tykcoktx.html