zoukankan      html  css  js  c++  java
  • python之路---封装

    【封装】

             隐藏对象的属性和实现细节,仅对外提供公共访问方式。

    【好处】 

    1. 将变化隔离; 

    2. 便于使用;

    3. 提高复用性; 

    4. 提高安全性;

    【封装原则】

          1. 将不需要对外提供的内容都隐藏起来;

          2. 把属性都隐藏,提供公共方法对其访问。

                                     私有变量和私有方法                             

     私有变量                              

    class Person:
        def __init__(self,name):
            self.__name = name
        def __eat(self):
            print( "{} is pig".format(self.__name))     # 类里可以使用私有属性
    p = Person('femgyu')
    # print(p.__name)       # 无法调用私有方法
    print(p._Person__name)  # fengyu         变形后可以调用,但是这种方法不提倡,因为私有属性或方法就不应该在类外面调用
    # p.__eat()             # 无法调用私有方法
    p._Person__eat()        # femgyu is pig  变形后可以调用,但是这种方法不提倡,因为私有属性或方法就不应该在类外面调用

    这种自动变形的特点:

    1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

    2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

    3.在子类定义的__x不会覆盖父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

    针对上面的3,有一道经典面试题

    class A:
        def __init__(self):
            self.__func()
        def __func(self):
            print('A')
    class B(A):
        def __func(self):
            print('B')
    B()
    
    
    # 对比下面的代码
    
    class A:
        def __init__(self):
            self.func()
        def func(self):
            print('A')
    class B(A):
        def func(self):
            print('B')
    B()

    这种变形需要注意的问题是:

    1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

    2.变形的过程只在类的内部定义私有属性(或方法)时生效,在类外部定义私有属性(或方法)时,不会变形

    class Person:
        def __init__(self,name):
            self.__name = name
        def __eat(self):
            print( "{} is pig".format(self.__name))     # 类里可以使用私有属性
    p = Person('femgyu')
    print(p.__dict__)
    p.__age = 20
    print(p.__dict__)
    
    # 打印结果如下:
    {'_Person__name': 'femgyu'}
    {'_Person__name': 'femgyu', '__age': 20}

     私有方法                                          

    在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

    #正常情况
    >>> class A:
    ...     def fa(self):
    ...         print('from A')
    ...     def test(self):
    ...         self.fa()
    ... 
    >>> class B(A):
    ...     def fa(self):
    ...         print('from B')
    ... 
    >>> b=B()
    >>> b.test()
    from B
     
    
    #把fa定义成私有的,即__fa
    >>> class A:
    ...     def __fa(self): #在定义时就变形为_A__fa
    ...         print('from A')
    ...     def test(self):
    ...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
    ... 
    >>> class B(A):
    ...     def __fa(self):
    ...         print('from B')
    ... 
    >>> b=B()
    >>> b.test()
    from A

                                   三个装饰器函数                                    

     property属性            将方法伪装成属性                           

    在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:

    class Student(object):
        def get_score(self):
            return self.score
    
        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
    s = Student()
    s.set_score(99)
    print(s.get_score())
    
    # 可以任意修改分数
    s.score = 1000
    print(s.get_score())

    这显然不合逻辑。

    class Student(object):
        def get_score(self):
            return self._score
    
        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
    s = Student()
    s.set_score(60)
    print(s.get_score())
    
    # 设为私有属性后,就不可以随便修改分数了
    s.__score = 1000
    print(s.get_score())

    但是,上面的调用方法略显复杂,没有直接用属性这么直接简单。

    还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property装饰器就是负责把一个方法变成属性调用的:

    @property的实现比较复杂,我们先考察如何使用:

      把一个getter方法变成属性,只需要加上@property就可以了,

      此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值。

    class Student(object):
    
        @property
        def score(self):
            return self._score
    
        @score.setter
        def 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
    s = Student()
    
    # 将方法变成属性进行赋值
    s.score = 60
    print(s.score)
    
    s.__score = 1000
    print(s.score)

      classmethod               (类方法)              

    类方法:类中的方法传入类cls,不传对象self

        类中的方法不需要对象去调用,不需要去实例化一个对象,直接用类名调用

    class A():
        role = 'dog'
    
        @classmethod
        def func(cls):
            print(cls.role)
    
    A.func()

     staticmethod                    (静态方法)            

    静态方法:类中的方法不需要传入对象self或者类cls

           直接用类名或对象名调用

    静态方法就是在类里面定义的普通函数,但也是该类的局部函数。

    class A:
        role = 'dog'
    
        @staticmethod
        def func():
            print(A.role)
    
    A.func()
  • 相关阅读:
    sql中别名加as和不加as的区别
    easyui 扩展 datagrid 数据网格视图
    asp.net 版本一键升级,后台直接调用升级脚本
    SQLserver 还原数据库报“指定转换无效”的错的解决方案
    sql视图显示数据不对应
    django channels 实现实时通讯,主动推送
    django orm信号机制 + apschedule 定时任务
    django 使用原始SQL语句方式
    Django model 常用查询(搬运来备份的)
    Python3+ Django2.7开发web排坑记006 apache+wsgi部署应用
  • 原文地址:https://www.cnblogs.com/yanyufeng/p/9630113.html
Copyright © 2011-2022 走看看