zoukankan      html  css  js  c++  java
  • Python 类封装 property相关装饰器 接口抽象类abc模块 鸭子类型

    一 封装

    1.什么是封装:对外部隐藏内部的属性和细节方法,仅提供简单的访问接口。(注意:封装有隐藏的意思但不是单纯的隐藏)

    2.封装的目的:限制外界对内部数据的访问,提高内部数据的安全性和隔离复杂度。

      封装属性:提高数据的安全性

      封装方法:隔离复杂度

    3.python中属性的权限分为两种

      1.公开的:

                         没有任何限制 谁都能访问

           2.私有的:

                        只有当前类本身能够访问

            默认为公共的

    4.封装使用:

    封装语法:

    __属性名或方法名

    封装属性
    class Student:
    
        def __init__(self,name,age,gender,id_card):
            self.name = name
            self.age = age
            self.gender = gender
            self.__id_card = id_card
    
        def show_id_card(self):
            # 可以在这里添加额外的任何逻辑代码 来限制外部的访问
            
            #注意:在类的内部 可以访问
            print(self.__id_card)
    
    s = Student('jack',18,'man',32132111)
    # print(s.id_card) # 报错没有这个属性
    # print(s.__id_card) # 报错内部封装了无法访问
    s.show_id_card() # 32132111 通过函数在类内部访问拿到结果
    
    s.__id_card = 1233
    print(s.__id_card) # 1233 访问的不是原来被封装的属性,而是在对象中添加了__id_card
    print(s.__dict__) # 'name': 'jack', 'age': 18, 'gender': 'man', '_Student__id_card': 32132111, '__id_card': 1233}
    View Code
    class ATM:
        def withdraw(self):
            self.__user_auth()
            self.__input_money()
            self.__save_record()
            # 输入账号和密码
            # 显示余额
            # 输入取款金额
            # 保存记录
        def __user_auth(self):
            print("请输入账号密码....")
    
        def __input_money(self):
            print("余额为100000000,请输入取款金额!")
    
        def  __save_record(self):
            print("记录流水....")
    
    a = ATM()
    # a.__user_auth() # 报错__user_auth()被封装了无法访问
    # 通过内部直接访问
    a.withdraw() # 请输入账号密码.... 余额为100000000,请输入取款金额! 记录流水.... 
    View Code

    5.封装的原理(不建议使用这种方式访问被封装的属性和方法)

    python是通过 变形的方式来实现的封装
    如何变形 在名称带有双下划线开头的变量名字前添加_类名  如_Person__id_card
    当然通过变形后的名字可以直接访问被隐藏的属性  但通过不应该这么做
    变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形  就是普通属性 
    
    class Student:
    
        def __init__(self, name, age, gender, id_card):
            self.name = name
            self.age = age
            self.gender = gender
            self.__id_card = id_card
         # 封装方法
        def __say(self):
            print('hello')
    
        def show_id_card(self):
            # 可以在这里添加额外的任何逻辑代码 来限制外部的访问
    
            # 在类的内部 可以访问
            print(self.__id_card)
    s = Student('jack',18,'man',32132111)
    
    # print(s.__id_card) # 报错内部封装了无法访问
    # print(s._Student__id_card) # 通过变形拿到结果32132111 (被封装的属性名其实变成了'_Student__id_card')
    s.show_id_card() # 32132111 通过函数在类内部访问拿到结果
    
    # s.__id_card = 1233
    # print(s.__id_card) # 1233 访问的不是原属性,而是在对象中添加了__id_card
    print(s.__dict__) # 'name': 'jack', 'age': 18, 'gender': 'man', '_Student__id_card': 32132111, '__id_card': 1233} 
    View Code

    访问封装属性和方法的正确方式(Property装饰器)

    1.作用:将一个方法伪装成普通属性,访问的时候和访问普通属性一样不需要加()。

    2.

    class Teacher:
        def __init__(self,name,age,salary):
            self.name = name
            self.age = age
            self.__salary = salary
    
        @property  # getter   # 用于访问私有属性的值   也可以访问普通属性
        def salary(self):
            return self.__salary
    
        @salary.setter   # 用来设置私有属性的值  也可以设置普通属性
        def salary(self,new_salary):
            self.__salary = new_salary
    
        @salary.deleter # 用来设置私有属性的值  也可以删除普通属性
        def salary(self):
            # print("can not delete salary!")
            del self.__dict__["_Teacher__salary"]
    
    t = Teacher('jack',18,1000)
    print(t.salary) # 1000 此处的salary是一个函数相当于t.salary()主要是用于访问被封装的属性和方法
    
    与property相关的 两个装饰器 
    property
          对象点被装饰的方法触发(一般用于获取封装属性的值)
    
    setter 
    
    ​    用点语法 给属性赋值时触发   (一般用于设置,给对象设置属性)
    
    deleter 
    
    ​    用点语法删除属性时触发 (一般用于删除属性的值)
    View Code

    property 可以用来实现计算属性

    class Person:
        def __init__(self,name,height,weight):
            self.name = name
            self.height = height
            self.weight = weight
            # self.BMI = weight / (height ** 2)
    
        @property
        def BMI(self):
            return self.weight / (self.height ** 2)
    
        @BMI.setter
        def BMI(self,new_BMI):
            print("BMI 不支持自定义.....")
    
    
    p = Person("egon",1.7,80)
    print(p.BMI)
    p.BMI = 10
    View Code

    二 接口和抽象类

    1.什么是接口:

    接口是一组功能的集合,但是接口中仅包含功能的名字,不包含具体的实现代码

    接口本质是一套协议标准,遵循这个标准的对象就能被调用

    2.

    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)
    View Code

    3.

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

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

    问题:

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

    抽象类

    1.什么是抽象类:

    指的是包含抽象方法(没有函数体的方法)的类, 用@abc.abstractmethod 装饰器

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

    2.

    抽象类的特点:

    不能直接实例化 必须有子类覆盖了所有抽象方法后才能实例化子类

    与接口的区别:

    接口是指只有方法声明而没有实现体 , 接口中所有方法都是抽象的

    import abc
    
    class Test(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def say_hi(self):
            pass
    
    class TT(Test):
    
        def say_hi(self):
            print("i am TT obj")
    
    t = TT()
    t.say_hi()
    View Code

    三 鸭子类型

    1.什么是鸭子类型:多个不同类对象具备相同的属性和方法

    2.案例:对象作为另一个对象的方法参数(注意和组合区分)

    class PC():
    
        def conntent_device(self, usb_device):
            usb_device.open()
            usb_device.work()
            usb_device.close()
    
    class Mouse:
        # 实现接口规定的所有功能
        def open(self):
            print("mouse opened")
    
        def work(self):
            print("mouse working...")
    
        def close(self):
            print("mouse closed")
    
    mouse = Mouse()
    pc = PC()
    
    pc.conntent_device(mouse)
    
    
    
    class KeyBoard:
        def open(self):
            print("KeyBoard opened")
    
        def work(self):
            print("KeyBoard working...")
    
        def close(self):
            print("KeyBoard closed")
    
    key1 = KeyBoard()
    
    # 如果key1的特征和行为都像USB设备 那就把它当做USB设备来使用
    # 对于使用者而言可以不用关心这个对象是什么类,是如如何是实现,
    pc.conntent_device(key1)
  • 相关阅读:
    [JS]格式化Date和分析格式化Date字符串的JS代码
    发布一个实用美观的Vista Sidebar Gadget (代表博客园参赛)
    2月8号N706从深圳回湖南,有没有同行的,呵呵
    LiveWriter测试
    自动内容滚动条[WinForm控件]
    关于Ajax的一揽子工程(1)
    “做事先做人”实战
    成熟度即流程
    金秋游故宫
    html块状元素、内联元素
  • 原文地址:https://www.cnblogs.com/tfzz/p/11251040.html
Copyright © 2011-2022 走看看