zoukankan      html  css  js  c++  java
  • 面向对象之封装

    type:是所有类的类型,所有类的类型默认是type。

    一 封装

     1 什么叫做封装:就是将自己想要隐藏起来的内容给隐藏起来。

      封装的原则:1.1将不需要对外提供的内容隐藏起来;1,2将属性隐藏起来,提供公共方法对其访问。

     2 私有属性:self.__属性名

     3 私有的静态属性:__静态属性名

     4 私有方法:def  __函数名(self):

    # class Teacher:
    #     __zhiwei='laoshi'      #创建私有静态属性
    #     def __init__(self,name,pwd):
    #         self.name=name
    #         self.__pwd=pwd        #创建自己的私有的属性
    #     def __pwd_1(self):       #创建自己的私有方法
    #         print(self.__pwd)
    

     5 对象.__dict__:查看自己的属性。

    # class Teacher:
    #     def __init__(self,name,pwd):
    #         self.name=name
    #         self.__pwd=pwd
    #     def pwd(self):
    #         print(self.__pwd)
    # fang=Teacher('fang',123)
    # fang.pwd()
    # print(fang._Teacher__pwd)
    # fang._Teacher__pwd=999   #找到密码就可以修改密码了
    # print(fang.__dict__)     #查看自己 的属性
    

      调用自己的私有属性,静态属性和方法时,都要在前面加上(_类名)。私有的方法还可以在类的内部调用。

    # class Teacher:
    #     def __init__(self,name,pwd):
    #         self.name=name
    #         self.__pwd=pwd        #创建自己的私有的属性
    #     def __pwd_1(self):       #创建自己的私有方法
    #         print(self.__pwd)
    # fang=Teacher('fang',123)
    # fang._Teacher__pwd_1()     #调用自己的私有方法
    # print(fang._Teacher__pwd)
    # fang._Teacher__pwd=999   #找到密码就可以修改密码了
    # print(fang.__dict__)     #查看自己的属性
    

      父类的私有方法,私有静态属性,私有属性都只能在自己的内部调用,不能在子类中调用

      封装的应用场景: 1 有一些方法的返回值只是用来中间结果;2 父类的一些属性和方法不希望子类来调用。

      封装的好处有:1 将变化隔离;2 便于使用;3 提高复用性;4 提高安全性

    封装的两个层面

    封装其实分为两个层面,但无论哪种层面的封装,都要对外界提供好访问你内部隐藏内容的接口(接口可以理解为入口,有了这个入口,使用者无需且不能够直接访问到内部隐藏的细节,只能走接口,并且我们可以在接口的实现上附加更多的处理逻辑,从而严格控制使用者的访问)

    第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装]

    class Teacher(People):
        def __init__(self,name,age,sex,level,salary):
            self.name=name
            self.age=age
            self.sex=sex
            self.level=level
            self.salary=salary
        def foo(self):
            print('from sb')
    t1=Teacher('egon',81,'girl',-10,3000)
    t1.foo()
    
    
    
    #foo()就是这种封装
    View Code

    对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口

    第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。

    在python中用双下划线的方式实现隐藏属性(设置成私有的)  如下:

    # class People:
    #     __school='oldboy'
    #     def __init__(self,name,age,sex):
    #         self.name=name
    #         self.__age=age
    #         self.__sex=sex
    #     def __foo(self):
    #         print('from your')
    #
    # t1=People('egon',81,'girl')
    # # print(t1._People__age)
    # t1._People__foo()
    View Code
    class Teacher:
        __school="oldboy"    #_Teacher__school
        def __init__(self,name,salary):
            self.name=name
            self.__salary=salary   # _Teacher__salary
        def foo(self):              #_Teacher__foo
            print("====>",self.__salary)
            #调用时已经变成   print("====>",self._Teacher__salary)
    t=Teacher('egon',30000)
    print(t.foo())
    View Code

    这种自动变形的特点:

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

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

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

    注意:对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了

    这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N
    复制代码
    >>> a=A()
    >>> a._A__N
    0
    >>> a._A__X
    10
    >>> A._A__N
    0
    复制代码

    变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形

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

    #正常情况
    >>> 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
    View Code
    #把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
    View Code

    python并不会真的阻止你访问私有的属性,模块也遵循这种约定,如果模块名以单下划线开头,那么from module import *时不能被导入,但是你from module import _private_module依然是可以导入的

    其实很多时候你去调用一个模块的功能时会遇到单下划线开头的(socket._socket,sys._home,sys._clear_type_cache),这些都是私有的,原则上是供内部调用的,作为外部的你,一意孤行也是可以用的,只不过显得稍微麻烦一点点

    python要想与其他编程语言一样,严格控制属性的访问权限,只能借助内置方法如__getattr__,详见面向对象进阶

    二 面向对象中的常用装饰器

     property装饰器:将一个类中的方法伪装成一个属性,调用时后面可以不用加上括号。

      property装饰器的好处是:将一个类的函数定义定义成特性以后,对象在去是使用(对象.属性)时,根本无法察觉自己的属性是执行了一个函数后计算出来的,这种特性的使用方式遵循了统一访问的原则。

     setter:修改属性:将方法伪装成属性修改。

    # class Shop:
    #     discount=0.75
    #     def __init__(self,s_name,price):
    #         self.s_name=s_name
    #         self.__price=price
    #     @property
    #     def price(self):
    #         return self.__price*self.discount
    #     @price.setter
    #     def price(self,new_price):
    #         self.__price=new_price
    # apple=Shop('apple',5)
    # print(apple.price)
    # apple.price=8
    # print(apple.price)
    

     deleter:删除属性:将方法伪装成属性删除。

     classmethod:类的装饰器。将对象方法装饰成类方法。必须传入一个类的参数(cls)。

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

     staticmethod:静态方法装饰器,将对象方法装饰成静态方法

    class A:
        @staticmethod
        def func():
            print('func')
    A.func()
    

      完全使用面向编程的时候,不用将函数独立的放在类的外部,在类的方法上面加上staticmethod装饰器,就可以将方法编程一个普通的函数,也叫做静态方法。

      并且这个函数完全不需要依赖于对象的属性和类的属性。

      静态方法:没有必须传的参数。

      类方法:不需要使用对象的属性,但可以使用类的属性,必须传入一个类;还可以使用类方法,不需要实例化一个对象。

      普通方法:必须传入一个对象可以使用对象的属性和类的属性

    面向对象封装方式:1 public:其实就是不封装,对外是公开的。;2 private:这种封装对谁都不公开。

    三 特性

    什么事特性:property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回
    BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
    # class People:
    #     def __init__(self,name,age,sex,height,weight):
    #         self.__name=name
    #         self.__age=age
    #         self.__sex=sex
    #         self.__height=height
    #         self.__weight=weight
    #     @property   #bmi=property(bmi)
    #     def bmi(self):
    #         res=self.__weight / (self.__height ** 2 )
    #         print('name %s bmi %s'%(self.__name,res))
    
    #
    # egon=People('egon',18,'male',1.79,70)
    # egon.bmi
    View Code
    当property函数装饰后,返回的结果是一个数据数学,property函数装饰后,还可以有增删改的作用,调用就可以使用
    例二
    # class People:
    #     def __init__(self,name,age,sex,height,weight):
    #         self.__name=name
    #         self.__age=age
    #         self.__sex=sex
    #         self.__height=height
    #         self.__weight=weight
    #     @property   #name=property(name)
    #     def name(self):
    #         print(self.__name)
    #     # @name.setter
    #     # def name(self,val):
    #     #         self.__name=val
    #
    #     @name.deleter
    #     def name(self):
    #         raise PermissionError('不让删')
    #
    # egon=People('egon',18,'male',1.79,70)
    # egon.name                #egon
    #
    # del egon.name
    #
    View Code
    为什么要用property:将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

     
  • 相关阅读:
    HTML元素解释
    Java命名规范
    HDU 1058 Humble Numbers(DP,数)
    HDU 2845 Beans(DP,最大不连续和)
    HDU 2830 Matrix Swapping II (DP,最大全1矩阵)
    HDU 2870 Largest Submatrix(DP)
    HDU 1421 搬寝室(DP)
    HDU 2844 Coins (组合背包)
    HDU 2577 How to Type(模拟)
    HDU 2159 FATE(二维完全背包)
  • 原文地址:https://www.cnblogs.com/fangjie0410/p/7565125.html
Copyright © 2011-2022 走看看