zoukankan      html  css  js  c++  java
  • Python()- 面向对象三大特性----封装


    封装:

    【封装】
             隐藏对象的属性和实现细节,仅对外提供公共访问方式。
    【好处】 
    1. 将变化隔离; 
    2. 便于使用;
    3. 提高复用性; 
    4. 提高安全性;
    【封装原则】
          1. 将不需要对外提供的内容都隐藏起来;
          2. 把属性都隐藏,提供公共方法对其访问。


    广义封装:
    把一些属性和方法放到类里,这本身就是一种封装

    class Foo:
      role = ‘class’
      def func(self):
        pass

    狭义上的:
    把属性和方法藏在类里,只能在类内部调用,不能在外部使用

    class Dog:
        __role = 'dog'   #私有的静态属性   (相当于内部自动变成 _Dog__role)
        def __discount(self): #私有的方法
            print('in __func')
    
        def price(self):
            self.__discount()   #私有的对象属性
            
        def func(self):
            print(Dog.__role)       #内部可以调用私有属性
    
    print(Dog.__dict__)
    print(Dog._Dog__role)       #知道有这种查看方法就行,一般不要用,这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
    
    {
    '__module__': '__main__', '_Dog__role': 'dog',.......} _Dog__role相当于内部外运加上了(_类名) #dog 类似加了一层密码 ------------------------ d = Dog() d.func() #内部调用 #dog

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

    #把fa定义成私有的,即__fa
    class A:
        def __fa(self):         #在定义时就变形为_A__fa
            print('from A')
        def test(self):
            self.__fa()         #这个self.__fa()  实际上是self._A__fa()   所以调用的是A内部的def__fa()
    
    class B(A):
        def __fa(self):
            print('from B')
    
     b=B()
     b.test()
    from A

    ================

    私有的不能被继承:

    class A:
        def __fa(self):         #在定义时就变形为_A__fa
            print('from A')
    
    class B(A):
        def __init__(self): 
            self.__fa()         #  实际上是self._B__fa() 
    
    b=B()

    执行会报错:AttributeError: 'B' object has no attribute '_B__fa'

    ==============

    狭义封装小结:
    私有属性: 静态属性,方法,对象属性 3种
    内部能调用,外部不能
    不能被继承
    当有一个属性,不想被外部使用,也不想被子类继承,只想内部使用,就定义成私有的
    ========================================================

    @property 伪装

    property: 伪装 (__变量 配合起来就很强大了)

    @property: 把一个方法伪装成一个属性

    1.属性的值是方法的返回值
    2.这个方法就不能有参数

    --------------
    例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)

    成人的BMI数值:
    过轻:低于18.5
    正常:18.5-23.9
    过重:24-27
    肥胖:28-32
    非常肥胖, 高于32
      体质指数(BMI)=体重(kg)÷身高^2(m)
      EX:70kg÷(1.75×1.75)=22.86

    class Person:
        def __init__(self,name,height,weight):
            self.name = name
            self.height = height
            self.__weight = weight
    
        @property                       # 只是伪装作用
        def bmi(self):                  # 方法不能有参数
            return self.__weight / (self.height ** 2)
    
    kit = Person('kitty',1.75,85)
    print(kit.bmi)                          #kit.bmi  相当于  kit.bmi()
    #27.755

    如果 print(kit.bmi()) 就相当于 print(27.755()) 报错:TypeError: 'float' object is not callable
    --------------------------------------------------------------------------------------------------------------------------

    class Goods:
        __discount = 0.8   #静态属性
        def __init__(self,name,price):
            self.__name = name
            self.__price = price  #原价
        @property
        def name(self):
            return self.__name
    
        @property
        def price(self):   #折后价
            return self.__price * Goods.__discount
    
    apple = Goods('苹果',10)
    print(apple.price)
    apple.price = 100     报错:AttributeError: can't set attribute (安全:属性不能随便修改)
    print(apple.price)
    # __私有+property
    #让对象的属性变得更安全了  

    -------------------------------------------------------------------------------

      property    setter

    例题三:

    修改价格,加了一个if判断

    class Goods:
        __discount = 0.8   #静态属性
        def __init__(self,name,price):
            self.__name = name                   #将所有的数据属性都隐藏起来   
            self.__price = price  #原价
        @property
        def name(self):
            return self.__name              #obj.name访问的是self.__name(这也是真实值的存放位置)
    
        @name.setter            setter的位置只能传一个参数 obj.name = 'apple'
        def name(self,new_name):
            self.__name = new_name
    
        @property
        def price(self):   #折后价                     #在设定值之前进行类型检查
            return self.__price * Goods.__discount           #通过类型检查后,将值value存放到真实的位置self.__name
    
        @price.setter       #绕了一大圈,就为了修改属性这个简单的操作,目的是 加个 if 判断
        def price(self,new_price):   #修改原价
            if type(new_price) is int:      #必须是int类型
                self.__price = new_price
        
        @price.deleter
        def price(self):
            raise TypeError('不能修改')         #主动触发异常
    
    apple = Goods('苹果',10)
    print(apple.price)
    #8.0
    apple.price = 100   #settrt                 改变的是对象的属性
    print(apple.price)   #property
    #80.0
    -----------
    banana = Goods('香蕉',10)
    print(banana.price)   
    #16.0 
    print(apple.price)              #创建新对象,苹果的价格没有变化
    #80.0
    -------------
    del apple.price     # TypeError: 不能修改

    封装:

      @property @price.setter @price.deleter
      1.方法伪装成数据属性 (例题一:print(kit.bmi) )
      2.__私有+property, 让对象的属性变得更安全了 (例题二:修改价格,报错)
      3.获取到的对象的值可以进行一些加工 (例题三:修改价格,成功, 但是只能传一个参数)
      4.修改对象的值的同时可以进行一些验证 (例题三:判断输入的是否是数字)
    ========================================================

    1.如果只用@property, 属性就是固定的了,不能更改了
    2.为什么setter 呢?
    就是每次操作,都可以 if判断, raise主动触发异常 等等操作
    让对象 的属性变得更安全了
    -------------------------------------------------------------------------------

    =================================

    class Foo:
        # @property                       
        def AAA(self):
            print('get的时候运行我啊')
    
        @AAA.setter  # 如果没有@property  报错:AttributeError: 'function' object has no attribute 'setter' 
        def AAA(self, value):
            print('set的时候运行我啊')
    
        @AAA.deleter
        def AAA(self):
            print('delete的时候运行我啊')
    
    
    # 只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
    f1 = Foo()
    f1.AAA  # property
    f1.AAA = 'aaa'  # setter
    del f1.AAA  # deleter
    # get的时候运行我啊
    # set的时候运行我啊
    # delete的时候运行我啊

    ============================

    类方法:@classmethod

    class Goods:
        __discount = 0.8            # 想把类的静态属性改了
    
        def change_discount(self,new_discount):     
            self.__discount = new_discount
        
        def get_discount(self):
            return self.__discount
    
    # Goods._Goods__discount = 1     #不能用这个
    apple = Goods()
    print(Goods._Goods__discount)       # 0.8
    apple.change_discount(0.75)         
    print(apple.get_discount())             # 0.75     类的实例对象修改的是对象自己的属性
    print(Goods._Goods__discount)       # 0.8     但是类的静态变量没变

    ----------------------

    class Goods:
        __discount = 0.8
    
        @classmethod  # 类方法
        def change_discount(cls, new_discount):  # cls  不需要self参数,直接传 类
            cls.__discount = new_discount
    
        @classmethod
        def get_discount(cls):
            return cls.__discount
    
    
    # 不需要创建对象
    print(Goods.get_discount())
    # 0.8
    Goods.change_discount(0.75)
    print(Goods.get_discount())  # 类的属性改变了
    # 0.75

    ============================
    类方法

    调用:不需要实例化 直接用类名调用就好
    定义:不用接受self参数,默认传cls,cls就代表当前方法所在的类
    什么时候用类方法?
    需要使用静态变量 且 不需要和对象相关的任何操作的时候

    =========================

    静态方法:@staticmethod

    先来看一段代码

    class A:
        def func():  # 没有self,  有红色下划线        (这已经是一个静态方法了)
            print(123)
    
    
    A.func()
    # 123                #也不报错       但是不符合规范

    定义一个静态方法,要使用@staticmethon

    class A:
        @staticmethod           #如果要定义一个不传self参数的方法,要加@staticmethon  这样就不报错了
        def func(name,age):  #静态方法
            print(name,age)
    A.func('kitty',18)
    #'kitty',18

    和普通的调用函数没有什么区别了

    ========================

    静态方法:
    如果这个方法 ,既不需要操作静态变量,也不需要使用对象相关的操作,就用静态方法
    ---------------------------------------------------------------------------------

    面向对象编程:

    什么是面向对象编程?
    面向对象是一种思想,但是它也有一种规范,假如整篇用面向对象编程,那么整个程序里面不可以写除了类以外的其他东西,不可以定义函数,所有的函数必须定义到类里面.

    staticmethod--专门为面向对象编程提供的一个方法
    它完全可以当做普通函数去用,只不过这个函数要通过类名.函数名调用
    其他 传参 返回值 完全没有区别

    ======================================

    class A:
        @staticmethod
        def func1(name):  # 静态方法
            print(123)
    
        @classmethod
        def func2(cls):  # 类态方法
            print(123)
    
        def func3(self): pass
    
    
    a = A()
    print(a.func1)  # 静态方法
    # <function A.func1 at 0x00000000023188C8>
    print(a.func2)  # 类方法 : 绑定到A类的func
    # <bound method A.func2 of <class '__main__.A'>>
    print(a.func3)  # 普通方法:绑定到A类对象的func
    # <bound method A.func3 of <__main__.A object at 0x000000000231B160>>

    类里面,一共可以定义三种方法:

    1. 普通方法: self  对象调用 (方法里面用到对象相关的变量)
    2. 类方法: @classmethod      类调用 (方法里面用到类的静态变量或静态方法)
    3. 静态方法: @staticmethod   类调用 (方法里面啥都没有用到)

    (  类方法和静态方法 对象也可以调用,但没必要为了调用 去创建一个对象)

    =================================================

  • 相关阅读:
    作业2 四则运算
    自动生成小学四则运算题目(加强版)
    Oracle 转移符问题
    《一个程序猿的生命周期》有感
    自问自答总结
    The Last Reader Response——13-17
    读《构建之法》十一、十二章有感
    《构建之法》8,9,10,章有感
    第二天冲刺(个人工作)
    冲刺第一天(个人工作)
  • 原文地址:https://www.cnblogs.com/zhzhlong/p/8531594.html
Copyright © 2011-2022 走看看