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

    封装:

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

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

    class Foo:
    role = ‘classdef 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()

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

    狭义封装小结:
    私有属性: 静态属性,方法,对象属性 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: #如果是float类型,必须输入浮点数
    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())             # 1     类的实例对象修改的是对象自己的属性
    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()) #类的属性改变了

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

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

    类方法:必须通过类的调用,而且此方法的意义:就是对类里面的变量或者方法进行修改添加。

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

    静态方法:@staticmethod

    先来看一段代码

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

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

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

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

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

    静态方法: 就是一个不依赖类以及对象的一个普通函数,为什么在类里面?
    为了保证代码的一致性,可调控性,整洁性。

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

    面向对象编程:

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

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

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

    类里面,一共可以定义这三种方法:
    1.普通方法 self (方法里面用到对象相关的变量)
    2.类方法 cls (方法里面用到类的静态变量或静态方法)
    3.静态方法 (方法里面啥都没有用到)

    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   类调用 (方法里面啥都没有用到)

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

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

  • 相关阅读:
    javaweb消息中间件——rabbitmq入门
    virtual box 桥接模式(bridge adapter)下无法获取ip(determine ip failed)的解决方法
    Apache Kylin本地启动
    git操作
    Java学习总结
    Java中同步的几种实现方式
    hibernate exception nested transactions not supported 解决方法
    vue 中解决移动端使用 js sdk 在ios 上一直报invalid signature 的问题解决
    cookie 的使用
    vue 专门为了解决修改微信标题而生的项目
  • 原文地址:https://www.cnblogs.com/jin-yuana/p/10025287.html
Copyright © 2011-2022 走看看