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)
原文地址:https://www.cnblogs.com/tfzz/p/11251040.html