一、上节回顾:

复习:

面向对象的三大特性:  继承  多态  封装

(1)继承:

    #单继承:最常用的

  #多继承:钻石继承问题提现差别:经典类(深度优先)和新式类(广度优先),mro

       #新式类:super

  #父类子类调用方法的先后顺序

    #只要子类有就用子类的,子类没有就找父类

    #子类父类都想用,就先找子类,在子类中调用父类( super().hahaha() )

  #在多继承中,super不只是寻找当前的父类,而是依据mro顺序,

  #从A节点出发,依据广度优先排序查找下一类

、 #派生:子类中可能有,派生属性和派生方法

   #多态和鸭子类型

class Teacher:
    pass
class School:
    pass
class Professor(Teacher,School):
    pass
p1=Professor()
print(Professor.mro())
mro 查看继承顺序
class Parentclass1:  #定义父类(基类或者超类)
    pass
class Parentclass2: #定义父类
    pass
class SubClass1(Parentclass1):  #单继承,基类是Parentclass1,派生类SubClass1
    pass                        #新建的类叫做派生类或者子类
class SubClass2(Parentclass1,Parentclass2):  #多继承
    pass
单继承和多继承 的说明
#查看继承
print(SubClass1.__bases__)  #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
print(SubClass2.__bases__)
查看继承
#继承和抽象
#抽象最主要的作用是划分类别,抽象只是分析和设计的过程
#继承:是基于抽象的结果,通过编程语言去实现它,
# 肯定是先经历抽象这个过程,才能通过继承的方式去表达抽象的结构
# 继承和重用性
class Animal:
    def eat(self):
        print("%s 吃"%self.name)
    def drink(self):
        print("%s 喝"%self.name)
    def shit(self):
        print("%s 拉"%self.name)
    def pee(self):
        print("%s 撒"%self.name)

class Cat(Animal):

    def __init__(self,name):
        self.name=name
        self.breed=""

    def cry(self):
        print("喵喵叫")
class Dog(Animal):

    def __init__(self,name):
        self.name=name
        self.breed=""

    def cry(self):
        print("汪汪叫")
##########执行########
c1=Cat("小白家的小黑猫")
c1.eat()
c2=Cat("小黑家的小白猫")
c2.drink()
d1=Dog("胖子家的小瘦狗")
d1.eat()
继承和重用性

 通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

class Animal:
    def __init__(self,name,aggressivity,life_value):
        self.name=name
        self.aggressivity=aggressivity
        self.life_value=life_value

    def eat(self):
        print("%s is eating"% self.name)
class Dog(Animal):
    pass

class Person(Animal):
    pass
egg=Person("egon",10,1000)
ha2=Dog("二愣子",50,1000)
egg.eat()
ha2.eat()
代码的继承(人和狗的例子)

派生(子类):

class Animal:
    """
    人和狗都是动物所以创造一个Animal基类
    """
    def __init__(self,name,aggressivity,life_value):
        self.name=name    #人和狗都有自己的昵称
        self.aggressivity=aggressivity #人和狗都有自己的攻击力
        self.life_value=life_value #人和狗都有自己的生命值

    def eat(self):
        print("%s is eating"% self.name)

class Dog(Animal):
    """
    狗类,继承Animal类
    """
    def bite(self,people):
        """
        派生:狗有咬人的技能y
        :param people:
        :return:
        """
        people.life_value-=self.aggressivity

class Person(Animal):
    def attack(self,dog):
        """
        派生:人有攻击狗的技能
        :param dog:
        :return:
        """
        dog.life_value-=self.aggressivity
    pass
egg=Person("egon",10,1000)
ha2=Dog("二愣子",50,1000)
print(ha2.life_value)
egg.attack(ha2)
print(ha2.life_value)
派生的例子(人和狗)

super:

在python3中,子类执行父类的方法也可以直接用super方法.

class A:
    def hahaha(self):
        print("A")
class B(A):
    def hahaha(self):
        super().hahaha()
        #super(B,self).hahaha()
        #A.hahaha(self)
        print("B")
a=A()
b=B()
b.hahaha()  #A B
super(B,b).hahaha() #A
子类继承父类的两种方法

派生:

class Animal:
    """
    人和狗都是动物所以创造一个Animal基类
    """
    def __init__(self,name,aggressivity,life_value):
        self.name=name    #人和狗都有自己的昵称
        self.aggressivity=aggressivity #人和狗都有自己的攻击力
        self.life_value=life_value #人和狗都有自己的生命值

    def eat(self):
        print("%s is eating"% self.name)
#
class Dog(Animal):
    """
    狗类,继承Animal类
    """
    def __init__(self,name,breed,aggressivity,life_value):
        super().__init__(name,aggressivity,life_value) #执行父类Animal的init方法
        self.breed=breed #派生出了新属性
    def bite(self,people):
        """
        派生:狗有咬人的技能y
        :param people:
        :return:
        """
        people.life_value-=self.aggressivity
    def eat(self):
        #Animal.eat(self)
        #super().eat()
        print("from Dog")

class Person(Animal):
    """
    人类,继承Animal类
    """
    def __init__(self, name,aggressivity, life_value,money):
        #Animal.__init__(self,name,aggressivity,life_value)
        #super(Person,self).__init__(name,aggressivity,life_value)
        super().__init__(name, aggressivity, life_value)  # 执行父类Animal的init方法
        self.money = money  # 派生出了新属性
    def attack(self,dog):
        """
        派生:人有攻击狗的技能
        :param dog:
        :return:
        """
        dog.life_value-=self.aggressivity
    def eat(self):
        # super().eat()
        Animal.eat(self)
        print("from Person")

egg=Person("egon",10,1000,600)
ha2=Dog("二愣子","哈士奇",50,1000)
print(egg.name)
print(ha2.name)
egg.eat()
egg.attack(ha2)
print(ha2.life_value)
super 派生

通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师

class Teacher:
    def __init__(self,name,gender):
        self.name=name
        self.gender=gender
    def teach(self):
        print("teaching")
class Professor(Teacher):
    pass
p1=Professor("egon","male")
p1.teach()
# teaching

(2)多态:

  一种事物的多种形态叫做多态

class Animal:pass
class Dog(Animal):pass
class Cat(Animal):pass

(3)鸭子类型:

  #对于某一些方法来说,可以无差别的对待几个类型就是鸭子类型

#python 不崇尚数据类型之间的继承关系

  #数据类型之间减少依赖关系,解耦

#写功能性的程序:以功能为导向

#写框架类的,或者模块类的,使用继承的同时还要考虑解耦

二、今日内容 :

抽象类和接口类:

  (1)不崇尚接口类

  (2)python本身支持多继承,没有接口专用的语法,但是我知道接口的概念

封装:

  (1)私有属性

  (2)将方法转换成属性的机制:@property

  (3)@classmethond @staticmethod

1、接口类

#接口类
#继承有两种用途:
# 一、继承基类的方法,并且做出自己的改变或者拓展(代码重用)
#二、声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名
# (就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

最基础的接口类(但是容易出问题)
class Alipay:
    """
    支付宝支付
    """
    def pay(self,money):
        print("支付宝支付了%s元"%money)

class Applepay:
    """
    apple pay 支付
    """
    def pay(self,money):
        print("apple pay 支付了%s元"%money)

def pay(payment,money):
    """支付函数,总体负责支付
    对应支付的对象和要支付的金额
    """
    payment.pay(money)

p=Alipay()
p1=Applepay()
pay(p,200)  #支付宝支付了200元
pay(p1,2000) #apple pay 支付了2000元

接口初成:手动报异常

class Payment:
    def pay(self):
        raise NotImplementedError
class Wechatpay(Payment):
    def fuqian(self,money):
        print("微信支付了%s元"%money)
p=Wechatpay()  #这里不报错
pay(p,200)  #这里报错了

接口编程:是依赖模板进行编程

from abc import ABCMeta,abstractmethod
#接口类,是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现
class Payment(metaclass=ABCMeta): #模板,接口类
    @abstractmethod   #装饰器接口类中的方法的,加上这个装饰器,自动检测子类中的方法名
    def pay(self,money):
        pass
    
class Ali_Pay(Payment):
    def pay(self,money):
        print("您使用的支付宝支付了%s元"%money)
class Apple_Pay(Payment):
    def pay(self,money):
        print("您使用的苹果支付了%s元"%money)
class Wechat_Pay(Payment):
    def pay (self,money):
        print("微信支付了%s元"%money)

def pay(obj,money):
    return obj.pay(money)

# apple=Apple_Pay()
# ali=Ali_Pay()
wechat=Wechat_Pay()
# pay(apple,100)  #apple.pay(100)
pay(wechat,200) #微信支付了200元
支付例子(依赖接口编程)
from abc import ABCMeta,abstractmethod
class Fly_Animal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):pass

class Swim_Animal(metaclass=ABCMeta):
    @abstractmethod
    def swim(self):
        pass

class Walk_Animal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):
        pass

class Frog(Walk_Animal,Swim_Animal):
    def walk(self):
        print("实现walk功能")

class Swan(Walk_Animal,Swim_Animal,Fly_Animal):pass
class Bird(Swim_Animal,Fly_Animal):pass
接口隔离原则

接口隔离原则:使用多个专门的接口,而不使用单一的总接口,而客户端不应该依赖那些不需要的接口

#一切皆文件
import abc  #利用abc模块实现抽象类

class All_file(metaclass=abc.ABCMeta):
    all_type="file"
    @abc.abstractmethod  #定义抽象方法,无序实现功能
    def read(self):
    # ‘子类必须定义读功能’
        pass
    @abc.abstractmethod  #定义抽象方法,无序实现功能
    def read(self):
    # ‘子类必须定义写功能’
        pass
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print("文本数据的读取方法")

    def write(self):
        print("文本数据的读取方法")

class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print("硬盘数据的读取方法")

    def write(self):
        print("硬盘数据的读取方法")

class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print("数据的读取方法")

    def write(self):
        print("进程数据的读取方法")
wenbenwenjian=Txt()
yingpanwenjian=Sata()
jinchengwenjian=Process()
#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.write()

print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
一切皆文件(抽象在python中的应用)

总结:

#接口类:

 (1)是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现

 (2)接口类不能被实例化,它只能被继承

 (3)支持多继承

#抽象类

  (1)模板  规范

  (2)抽象类可以实现一些子类共有的功能和属性\抽象类不鼓励多继承

    文件操作:打开文件、关闭文件、写文件、读文件

    硬盘操作:打开、关闭、读、写

    进程文件:打开 关闭、读、写

   (3)python没有接口概念,只能借助抽象类模块来实现接口类

    接口————java:没有多继承 Interface

文件的抽象化

from abc import ABCMeta,abstractmethod
class Base(metaclass=ABCMeta):
    def __init__(self,filename):
        self.filename=filename
        @abstractmethod  #抽象方法
        def open(self):
            return "file_handler"
        
        @abstractmethod
        def close(self):pass

        @abstractmethod
        def read(self): pass

        @abstractmethod
        def write(self): pass

class File(Base):
    def open(self):pass
    def close(self):pass
    def read(self):pass
    def write(self):pass
文件的打开关闭读写

2、封装

  封装:把一些实行和方法放在类里,这本身就是一种封装

  #封装:把属性和方法藏在类里,我只能在类内部调用,不能在外部使用

 (1)私有变量 

#其实这仅仅这是一种变形操作
#类内所有双下划线开头的名称如:__x都会自动变形成:_类名__x的形式:
class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__x=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print("from A")
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到
    #A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问
    #仅仅只是一种语法意义上的变形
私有变量

调用类内的私有静态属性

class Dog:
    __role="dog"  #私有的静态属性
    def func(self):
        print(Dog.__role)  #_类__名字
print(Dog.__dict__)
# print(Dog._Dog__role)  #不能这么调用
#从类的外面不能直接调用,在类内的使用加上了一层密码:_类名
d=Dog()
d.func()
调用类内的私有静态属性

私有的方法

class Dog:
    __role="dog"   #私有的属性
    def __discount(self):  #私有的方法
        print("in__func")

    def price(self):
        self.__discount()
私有的方法

总结:定义一个私有变量\属性\方法:__名字

  在类内部可以直接用:__名字

  在类的外部不能直接使用,如果一定要用,在私有方法之前加上:_类名,变成_类名__名字

  在类外的名字 通过__dict__就可以查看

例子:不需要的可以隐藏

class Room:
    def __init__(self,name,price,length,width):
        self.name=name
        self.price=price
        self.__length=length
        self.__width=width    #隐藏的长与宽
    def area(self):
        return self.__width*self.__length  
house=Room("小明",1000,22,33)
print(house.area())
例子:房子的面积(隐藏长与宽)

   私有的不能被继承

class A:
    def __func(self):
        print("__a_func")   #_A__func
class B(A):
    def __init__(self):
        self.func()      #_B__func
b=B()

结果报错

总结:私有的静态属性、方法、对象属性

    #使用__名字的方式调用,保证在类内部可以调用,外部不行

    #私有的不能被继承

    #当有一个名字。不想被外部使用,也不想被子类继承,只想在内部使用的时候就定义私有的

 

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

例一: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,weigth):
        self.name=name
        self.height=height
        self.weight=weigth

    def bmi(self):
        return self.weight/(self.height**2)
li= Person("",1.66,51)
print(li.bmi())
解释例子

#1)属性的值,是这个方法的返回值

#2)这个方法不能有参数

园的周长的例子:

import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 #计算面积

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长

c=Circle(10)
print(c.radius)
print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上
'''
输出结果:
314.1592653589793
62.83185307179586
'''
圆的周长和面积
#注意:此时的特性area和perimeter不能被赋值
c.area=3 #为特性area赋值
'''
抛出异常:
AttributeError: can't set attribute
'''

 超市打折的例子:  修改原价,隐藏原价价格

class Goods:
    __discount=0.8  #静态属性
    def __init__(self,name,price):
        self.name=name
        self.price=price  #原价

    @property
    def price(self):   #折后价
        return self.__price*Goods.__discount

    @price.setter     #只能传一个参数
    def price(self,new_price):  #修改原价
        self.__price=new_price
        if type(new_price) is int:   #座一次限制后,下面的价格修改就会变得安全
            self.__price=new_price

apple=Goods("苹果",10)
print(apple.price)
danana=Goods("香蕉",2.5)
print(danana.price)
apple.price=5
print(apple.price)
超市打折的例子

总结:  封装

  #__私有+property

  #让对象的属性变得更安全了

  #获取到的对象的值可以进行一些加工

  #修改对象的值的同时可以进行一些验证

补充:  setter和  property

class Foo:
    @property
    def AAA(self):
        print("get的时候运行我啊")
    @AAA.setter
    def AAA(self,value):
        print("set的时候运行我啊")

    @AAA.deleter
    def AAA(self):
        print("delete的时候运行我啊")
#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA="aaa"
del f1.AAA

怎么用:

class Goods:

    def __init__(self):
        # 原价
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price


obj = Goods()
obj.price         # 获取商品价格
obj.price = 200   # 修改商品原价
print(obj.price)
del obj.price     # 删除商品原价

关于删除:

class Goods:
    __discount=0.8
    def __init__(self,name,price):
        self.__name=name
        self.__price=price

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self,new_name):
        self.__name=new_name

    @name.deleter
    def name(self):
        del self.__name

    @property
    def price(self):
       return self.__price*Goods.__discount

    @price.setter
    def price(self,new_price):
        if type(new_price)is int:
            self.__price=new_price
apple=Goods("苹果",10)
# del apple.name
print(apple.name)
删除售卖的品种

(3)类方法

  @classmethod

class Goods:
    __discount=0.8
    @classmethod #类方法
    def change_discount(cls,new_discount):
        cls.__discount=new_discount*0.5

    @classmethod
    def get_discount(cls):
        return cls.__discount
# apple=Goods()
Goods.change_discount(0.75)
print(Goods.get_discount())

总结:

  类方法: 

    #调用:不需要实例化,直接用类名调用就好

    #定义:不用接受self参数,默认传cls,cls就代表当前方法所在的类

  #什么时候用类方法?

  #需要使用静态变量 且不需要和对象相关的任何操作 就使用静态方法

(4)静态方法

      @staticmethod

class A:
    @staticmethod
    def func(name):
        print(123)
A.func("alex")

总结:面向对象的编程:专门为面向对象编程提供的一个方法————staticmethod

  #它完全可以当做普通的函数去用,只不过这个函数需要通过类名.函数名调用

  #其他 传参 返回值 完全没有区别

绑定和非绑定:

class A:
    @staticmethod
    def func1(name):
        print(123)

    @classmethod
    def func2(name):
        print(123)

    def func3(self):pass
a=A()
print(a.func1)  #静态方法
print(a.func2)  #类方法:找到绑定到A类的func
print(a.func3)  #普通方法:绑定到A类对想的func

 

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

  普通方法 self

  类方法 cls   @classmrthod

  静态方法  @staticmethod

静态方法和类方法都是直接使用类名调用

普通方法:对象调用