面向对像之封装

---恢复内容开始---

封装

封装是什么?

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

好处:

  1、将变化隔绝

  2、便于使用

  3、提高安全性

  4、提高代码的复用性

   【封装的原则】

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

    2、把属性都隐藏,提供的公共访问方式对其访问

    3、外界不能直接访问

    4、内部依然可以使用

权限    

在python中只有两种权限

  1、公开、默认就是公开的

  2、私有的、只能有当前类自己使用

【私有变量和私有方法】

  在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

【私有变量】

【语法】

class Person:
    def __init__(self,id_number,name,age)
    	self.__id_number = id_number
        self.name = name
        self.age = age
   
p = Person("1111111111111","jack",29)

p.id_number = "222"

其实这仅仅是一种变形的操作
类中所有双下划线开头的名称如__c都会自动变形成:_类名__c的形式:


class A:
  _N = 0 # 类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的加上__ n 就会变成 _A__N
  def __init__(self):
    self.__m = 22   # 变形为 self,_A__m = 22
  def __ood(self):   #变形为 _A__ood
    print('from A ')
  def ber(self):
    self.__foo() #只有在内部才可以通过__ood的形式访问到。


# _A._A__N是可以访问到的,即这种操作并不严格意义上的限制外部访问,仅仅只是语法意义的变形

  这种自动变形的特点:

1、类中定义的__x只能再内部使用,如:self.__m,就引起了变形的结果.

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

3. 在子类定的__m是不会覆盖定义在父类中的__m , 因为子类中变形了:_子类名称__m, 而父类中的变形

 成为了: _父类名__m ,即时双下划线开头的属性继承给子类的时候子类也是无法覆盖的.

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

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

  2. 变形的过程只在类的内部生效,在定义后的复制操作,不会变形

私有方法  

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

正常情况下:

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):
        print('from A')
    def test(self):
        self.__fa()

class B(A):
    def __fa(self):
        print('From B')


b = B()
b.test()   #>>>from A

  封装与扩展性

  封装在于明确区分内外,使得类实现着可以修改封装内部的东西而不影响外部调用者的调用代码;而外部使用者只知道一个接口(函数),只要接口(函数)名,参数不变, 使用者永远不用改变代码. 只要接口的基础不变,则调用者或者说接入者都不要改变,

#类的设计者
class Room: def __init__(self, name, owner, width, length, high): self.name = name self.owner = owner self.__width = width self.__length = length self.__high = high def tell_area(self): # 对外界提供的接口,隐藏了内部的实现细节,此时我们想求的是面积 return self.__width * self.__length # 使用者 r1 = Room('卧室', 'kivn', 20, 20, 3) r1.tell_area() print(r1.tell_area()) 

#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码

"""
class Room:
    def __init__(self, name,owner, width, length, high):
        self.name = name
        self.owner = owner
        self.__width = width
        self.__length =  length
        self.__high= high
    def tell_area(self):  # 对外界提供了接口,隐藏内部的实现,此时我们想求得是体积,但是内部的逻辑已经更改了
        # 只需要修改以下一行代码就可实现,而且外部调用感知不知道,还是使用原来的方法,但是功能已经改变了
        return self.__length * self.__width * self.__high

# 对于使用者来说,调用的方法还是和原来的一样,根本不需要改变自己的代码,就可以用上新的功能了

r1 = Room('卧室', 'kivn', 20, 20, 3)
r1.tell_area()
print(r1.tell_area())

 接口:

 接口就是一组功能的集合,但是接口中仅包含功能的名字,不包含具体的功能代码,接口本质就是一套标准的协议,遵循这个标准的对象就能被调用

接口的目的就是为了提高扩展性:

例如一台电脑提前丁志义他哦标准的ubs通信协议,你只要遵循这标准的协议,你的设备就可以被电脑使用,前提是你的设备已经吧和电脑链接的和使用的固件已经写好并烧录到电脑里面

class USB:
    def open(self):
        pass

    def close(self):
        pass

    def  read(self):
        pass

    def write(self):
        pass

class Mouse(USB):
    def open(self):
        print("鼠标开机.....")

    def close(self):
        print("鼠标关机了...")

    def read(self):
        print("获取了光标位置....")

    def write(self):
        print("鼠标不支持写入....")


def pc(usb_device):
    usb_device.open()
    usb_device.read()
    usb_device.write()
    usb_device.close()

m = Mouse()
# 将鼠标传给电脑
pc(m)

class KeyBoard(USB):
    def open(self):
        print("键盘开机.....")

    def close(self):
        print("键盘关机了...")

    def read(self):
        print("获取了按键字符....")

    def write(self):
        print("可以写入灯光颜色....")

# 来了一个键盘对象
k = KeyBoard()
pc(k)

  

 在上述案例中,PC的代码一旦完成,后期无论什么样的设备 只要遵循了USB接口协议,都能够被电脑所调用 

接口主要是方便了对象的使用者,降低使用者的 学习难度,只要学习一套使用方法,就可以以不变应万变

问题:

如果子类没有按照你的协议来设计,也没办法限制他,将导致代码无法运行

property 属性

什么是property:

  property 是一种特殊的属性,访问它时会执行一段代码功能(函数)然后返回值

  通过方法来修改或者访问属性,本身没有什么问题,但是这给对象的使用者带来了麻烦,使用者必须要知道哪些是普通属性,哪些是私有属性,需要使用不同的方式来调用他们,property装饰就是为了使的调用的方式一样

有三个相关的装饰器

1、 property   改装饰器在获取属行的方法

2、 @函数名.setter  该装饰器用在修改属性的方法上面

3、 @函数名. deleter 这个装饰器使用在删除函数的属性使用方法

注意:

  函数名是被prooerty装饰的方法的名称,在内部会创建一个对象,变量名称就是函数名称,

所以在使用stter和deleter时,必须保证使用对象的名称去调用方法

class A:
    def __init__(self,name,key):
        self.__name = name
        self.__key = key

    @property
    def key(self):
        return self.__key

    @key.setter
    def key(self,new_key):
        if new_key <= 100:
            self.__key = new_key
        else:
            print("key 必须小于等于100")

    
    @key.deleter
    def key(self):
        print("不允许删除该属性")
        del self.__key
        
a = A("jack",123)
print(a.key)
a.key = 321
print(a.key)

 抽象类

抽象类指的是包含抽象的方法(没有函数体的方法)的类

作用: 可以限制子类必须类中定义的抽象方法

  python一般不会限制你必须怎么写,作为一个程序员,就应该遵守相关的协议:

    所以就有了鸭子类的说法:

      如果说一个对象长得像鸭子,走路像鸭子,那么他就是鸭子

你只要保证你的类按照相关的协议类编写,也是可以达到提高扩展性的目的

案例:

class Mouse:
    def open(self):
        print('鼠标已经通电了...')
    def close(self):
        print('鼠标已断电...')
def pc(usb_device):
    usb_device.open()
    usb_device.close()
m = Mouse()
pc(m)

  接口是一套协议规范,明确子类应该具备的功能;抽象类使用于要求子类必须按照协议中的规定来实现,然而python不推崇限制你的语法,我们可以自己设计鸭子的类型,可以让多个不同类对象具备相同的属性和方法

对使用者说,最好就是什么都不改变,以不变应万变,轻松的使用各种对象

\

---恢复内容结束---

温馨提示:由于系统有大概3~6分钟超时自动退出的规则,您在操作过程中需要关注下页面提醒并及时回应一下哦~及时回来喔

猜你喜欢

转载自www.cnblogs.com/ioipchina/p/11252238.html