python-抽象-接口-多态

抽象类

什么是抽象类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。抽象类是将一堆的类中抽象抽取相同的内容,其其中包括了数据的属性和函数的属性。
python中实现的抽象的类
看下面的代码:

class Wechatpay:
    def __init__(self, name, money):
        self.name = name
        self.money = money

    def pay(self):
        print('%s通过微信支付了%s元' % (self.name, self.money))


class Alipay:
    def __init__(self, name, money):
        self.name = name
        self.money = money

    def pay(self):
        print('%s通过支付宝支付了%s元' % (self.name, self.money))


# 为了归一化设计
def pay(person):  # 直接传入一个对象,对象调用pay方法 ,不管的alipay和Wechatpay
    person.pay()


# 实列化对象
ali = Alipay("Tom", 10000)
wch = Alipay("Jack", 100)

pay(ali)
pay(wch)

上述这样调用是没有任何的问题,但是某天,为了需求,需要添加applepay的功能,但是在定义的applepay中
没有定义pay方法,而是定义成为中文的汉语拼音fuqian的方法如下所示:

class ApplePay:
    def __init__(self, name, money):
        self.name = name
        self.money = money

    def fuqian(self):
        print('%s通过apple pay支付了%s元' % (self.name, self.money))

app = ApplePay("Tom", 1000)
app.fuqian()

上述通过ApplePay实例化的对象,调用的fuqian方法是没有任何的问题,当时为了归一化的设计,我们
在使用applyPay实例化的对象,将对象传入到pay函数中,则会出现下面的报错信息,没有pay的方法

pay(app)  # AttributeError: 'ApplePay' object has no attribute 'pay'

那怎么样处理这样的问题?
处理只要的问题,只能从规范的程度进行处理,在定义函数的时候,就必须设置相同的函数名,就如上述中ApplePay中方法fuqian应该改成和Alipay和WechatPlay中的pay,怎样在进行归一化的设计的时候,就不会出现找不到该方法了。在python中是使用abc模块来进行规范的,具体的使用方法如下所示:

from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):    # 抽象类

    @abstractmethod   # 如果我必须要实现pay方法,那么我需要给pay加一个装饰器
    def pay(self):
        pass   # 创建的这个pay并没有内容,
               # 之所以写一个pay是为了提醒所有子类你一定要实现一个pay方法

    @abstractmethod
    def back(self):
        pass

class Wechatpay(Payment):
    def __init__(self,name,money):
        self.name = name
        self.money = money
    def pay(self):
        print('%s通过微信支付了%s元'%(self.name,self.money))

class Alipay(Payment):
    def __init__(self,name,money):
        self.name = name
        self.money = money
    def pay(self):
        print('%s通过支付宝支付了%s元'%(self.name,self.money))

class ApplePay(Payment):
    def __init__(self, name, money):
        self.name = name
        self.money = money
    def pay(self):
        print('%s通过apple pay支付了%s元' % (self.name, self.money))
    def back(self):
        print('退款')

# 归一化设计
def pay(person):
    person.pay()

ApplePay('alex',20000)

特别注意的是,在类Payment中被语法糖装饰的函数,如果没有在子类中进行创建实现,那么在子类的实例化的时候,就会导致报错。如下所示:

from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):    # 抽象类

    @abstractmethod   # 如果我必须要实现pay方法,那么我需要给pay加一个装饰器
    def pay(self):
        pass   # 创建的这个pay并没有内容,
               # 之所以写一个pay是为了提醒所有子类你一定要实现一个pay方法

    @abstractmethod
    def back(self):
        pass

class Wechatpay(Payment):
    def __init__(self,name,money):
        self.name = name
        self.money = money
    def pay(self):
        print('%s通过微信支付了%s元'%(self.name,self.money))

class Alipay(Payment):
    def __init__(self,name,money):
        self.name = name
        self.money = money
    def pay(self):
        print('%s通过支付宝支付了%s元'%(self.name,self.money))

class ApplePay(Payment):
    def __init__(self, name, money):
        self.name = name
        self.money = money
    # def pay(self):  
    #     print('%s通过apple pay支付了%s元' % (self.name, self.money))
    # def back(self):
    #     print('退款')

# 归一化设计
def pay(person):
    person.pay()

ApplePay('alex',20000)

上述的代码中,在ApplePay将pay方法进行注释了,在进行ApplePay('alex',20000)实例化的时候,出现了下面的错误:

TypeError: Can't instantiate abstract class ApplePay with abstract methods back, pay

总结:

抽象类 :Payment这个类是一个抽象类
抽象类做什么事儿 : 约束所有的子类 必须实现被abstractmethod装饰的方法名
给我们的代码指定规范
特点 : 抽象类不能实例化,只是作为具体的类的规范
抽象类长什么样

class 类名(metaclass = 'ABCMeta'):

    @abstractmethod
    def 规定的方法名(self):pass

    @abstractmethod
    def 规定的方法名(self):pass

    @abstractmethod
    def 规定的方法名(self):pass

接口类

类只能单继承,所以抽象类 只能是所有的子类只有一个规范
java 当中没有多继承的类
接口 接口可以多继承
在python里没有接口的专用语法
我们只是通过类的多继承模仿接口的效果

from abc import ABCMeta,abstractmethod
class NormalAnnimal(metaclass=ABCMeta):
    @abstractmethod
    def eat(self):pass

    @abstractmethod
    def drink(self):pass
class FlyAnimal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):pass

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

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

和抽象类一样,基类多装饰的方法,子类中都必须去实现它,在java中,基类所定义的方法,通常只是定义,而不能实现,而在python中就没有那么对限制,可以去实现,但是一般也是只是定义方法,在子类中去实现。

总结:

  • 抽象类 是单继承的规范
  • 接口类 是多继承的规范

java中

  • 接口里面定义的所有的方法 都不能写具体的实现 pass
  • 抽象类里面定义的所有的抽象方法 内部是可以完成一些简单的代码

多态

多态指的是一类事物有多种形态
动物有多种形态:人,狗,猪

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')

文件有多种形态:文本文件,可执行文件

import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件
    @abc.abstractmethod
    def click(self):
        pass

class Text(File): #文件的形态之一:文本文件
    def click(self):
        print('open file')

class ExeFile(File): #文件的形态之二:可执行文件
    def click(self):
        print('execute file')

多态性

peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
    obj.talk()

鸭子类型
Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

# 二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass

总结:

# 鸭子类型
    # python当中写程序的一种特殊的情况
    # 其他语言中 正常的我们说一个数据类型具有某个特点,通常是通过继承来实现
        # 继承迭代器类,来证明自己本身是个迭代器
        # 继承可哈希的类,来证明自己本事是可哈希的
    # 但是所有的这些都不是通过继承来完成的
        # 我们只是通过一种潜规则的约定,如果具有__iter__,__next__就是迭代器
        # 如果具有__hash__方法就是可哈希
        # 如果具有__len__就是可以计算长度的
    # 这样数据类型之间的关系并不仅仅是通过继承来约束的
    # 而是通过约定俗成的关系来确认的

# 多态
    # 在传递参数的时候,如果要传递的对象有可能是多个类的对象
        # 我们又必须在语言中清楚的描述出到底是那一个类型的对象
        # 我们就可以使用继承的形式,有一个父类作为这些所有可能被传递进来的对象的基类
        # 基础类型就可以写成这个父类
        # 于是所有子类的对象都是属于这个父类的
    # 在python当中,因为要传递的对象的类型在定义阶段不需要明确,所以我们在python中处处都是多态
        # 数据的类型不需要通过继承来维护统一

原文地址:https://www.cnblogs.com/yangchangjie150330/p/10615522.html