Python 的 ABC 入门

举报
Q神 发表于 2023/06/24 16:22:16 2023/06/24
【摘要】 Python 的 ABC 基础知识是什么?它代表抽象基类,是Python类中基于抽象的概念。抽象是面向对象编程的一个组成部分。抽象就是我们所说的向用户隐藏程序的内部过程。以计算机鼠标为例,我们单击左键或右键,就会发生相应的操作,或者滚动鼠标滚轮,就会发生特定的任务。我们不知道内部功能,但我们确实知道单击此按钮即可完成我们的工作。抽象地讲,用户不知道内部功能,但熟悉该方法的用途。如果我们以模块...

Python 的 ABC 基础知识是什么?它代表抽象基类,是Python类中基于抽象的概念。抽象是面向对象编程的一个组成部分。

抽象就是我们所说的向用户隐藏程序的内部过程。以计算机鼠标为例,我们单击左键或右键,就会发生相应的操作,或者滚动鼠标滚轮,就会发生特定的任务。我们不知道内部功能,但我们确实知道单击此按钮即可完成我们的工作。

抽象地讲,用户不知道内部功能,但熟悉该方法的用途。如果我们以模块为例datetime,我们确实知道运行该datetime.now()函数将返回当前日期和时间,但不知道这是如何发生的。

Python 中的ABC

Python 不是一种完全面向对象的编程语言,但它支持抽象类和抽象等功能。我们无法直接在Python中创建抽象类,因此Python提供了一个名为abc的模块,它提供了定义抽象基类(ABC)的基础结构。

什么是抽象基类?它们为具体的类提供了蓝图。它们只是定义但没有实现,而是需要子类来实现。

定义ABC

让我们通过一个例子来了解如何定义一个带有抽象方法的抽象类。

from abc import ABC, abstractmethod

class Friend(ABC):

    @abstractmethod
    def role(self):
        pass

类Friend派生自模块ABC中的类abc,使其成为抽象类,然后在该类中@abstractmethod定义了一个装饰器来指示该函数角色是一个抽象方法。

abc模块有另一个类ABCMeta用于创建抽象类。

from abc import ABCMeta, abstractmethod

class Friend(metaclass=ABCMeta):

    @abstractmethod
    def role(self):
        pass

ABC在行动

现在我们将了解如何创建抽象类和抽象方法,然后通过继承在具体类中实现它。

from abc import ABC, abstractmethod


# Defining abstract class
class Friends(ABC):
    """abstract method decorator to indicate that the
    method right below is an abstract method."""

    @abstractmethod
    def role(self):
        pass


# Concrete derived class inheriting from abstract class
class Sachin(Friends):
    # Implementing abstract method
    def role(self):
        print('Python Developer')


# Concrete derived class inheriting from abstract class
class Rishu(Friends):
    # Implementing abstract method
    def role(self):
        print('C++ Developer')


# Concrete derived class inheriting from abstract class
class Yashwant(Friends):
    # Implementing abstract method
    def role(self):
        print('C++ Developer')


# Instantiating concrete derived class
roles = Sachin()
roles.role()
# Instantiating concrete derived class
roles = Rishu()
roles.role()
# Instantiating concrete derived class
roles = Yashwant()
roles.role()

在上面的代码中,我们创建了一个名为 的抽象类,并使用装饰器在类中Friends定义了抽象方法。role@abstractmethod

然后我们创建了三个具体的派生类 、SachinRishuYashwant,它们继承自该类并在其中Friends实现了抽象方法。role

然后我们实例化派生类并调用role使用类的实例来显示结果。

Python Developer
C++ Developer
C++ Developer

正如我们之前讨论的,抽象类提供了将方法实现到具体子类中的蓝图。

from abc import ABC, abstractmethod

class Details(ABC):
    @abstractmethod
    def getname(self):
        return self.name

    @abstractmethod
    def getrole(self):
        return self.role

    @abstractmethod
    def gethobby(self):
        return self.hobby


class Sachin(Details):
    def __init__(self, name="Sachin"):
        self.name = name
        self.role = "Python Dev"
        self.hobby = "Fuseball spielen"

    def getname(self):
        return self.name

    def getrole(self):
        return self.role

    def gethobby(self):
        return self.hobby


detail = Sachin()
print(detail.getname())
print(detail.getrole())
print(detail.gethobby())

在上面的代码中,我们为类创建了一个蓝图Details。然后我们创建了一个Sachin继承自 的类Details,并根据蓝图实现了方法。

然后我们实例化该类,然后打印、和Sachin的值。getnamegetrolegethobby

Sachin
Python Dev
Fuseball spielen

如果我们创建一个不遵循抽象类蓝图的类怎么办?

from abc import ABC, abstractmethod

class Details(ABC):
    @abstractmethod
    def getname(self):
        return self.name

    @abstractmethod
    def getrole(self):
        return self.role

    @abstractmethod
    def gethobby(self):
        return self.hobby


class Sachin(Details):
    def __init__(self, name="Sachin"):
        self.name = name
        self.role = "Python Dev"
        self.hobby = "Fuseball spielen"

    def getname(self):
        return self.name

    def getrole(self):
        return self.role


detail = Sachin()
print(detail.getname())
print(detail.getrole())

Python 在执行上述代码时会引发错误,因为该类Sachin不遵循类Details蓝图。

Traceback (most recent call last):
  ....
TypeError: Can't instantiate abstract class Sachin with abstract method gethobby

ABC的使用

正如我们在上面的示例中看到的,如果派生类不遵循抽象类的蓝图,则会引发错误。

这就是 ABC(抽象基类)在确保子类必须遵循该蓝图方面发挥重要作用的地方。因此我们可以说,从抽象类继承的子类必须遵循相同的结构并实现抽象方法。

ABC里面的具体方法

我们还可以在抽象类中定义具体方法。具体方法是有完整定义的普通方法。

from abc import ABC, abstractmethod

# Abstract class
class Demo(ABC):
    # Defining a concrete method
    def concrete_method(self):
        print("Calling concrete method")

    @abstractmethod
    def data(self):
        pass

# Derived class
class Test(Demo):

    def data(self):
        pass

# Instantiating the class
data = Test()
# Calling the concrete method
data.concrete_method()

在上面的代码中,concrete_method是在抽象类中定义的具体方法,并且使用类 Test 的实例调用该方法。

Calling concrete method

抽象类实例化

抽象类只能被定义而不能被实例化,因为它们不是具体类。Python 不允许为抽象类创建对象,因为没有实际的实现可以调用,而是需要子类来实现。

from abc import ABC, abstractmethod

class Details(ABC):
    @abstractmethod
    def getname(self):
        return self.name

    @abstractmethod
    def getrole(self):
        return self.role

class Sachin(Details):
    def __init__(self, name="Sachin"):
        self.name = name
        self.role = "Python Dev"

    def getname(self):
        return self.name

    def getrole(self):
        return self.role

# Instantiating the abstract class
abstract_class = Details()

输出

Traceback (most recent call last):
  ....
TypeError: Can't instantiate abstract class Details with abstract methods getname, getrole

我们收到错误消息,指出我们无法使用名为getname和的抽象方法实例化抽象类Details getrole

抽象属性

正如abc模块允许我们使用装饰器定义抽象方法一样@abstractmethod,它也允许我们使用装饰器定义抽象属性@abstractproperty

from abc import ABC, abstractproperty

# Abstract class
class Hero(ABC):

    @abstractproperty
    def hero_name(self):
        return self.hname

    @abstractproperty
    def reel_name(self):
        return self.rname

# Derived class
class RDJ(Hero):

    def __init__(self):
        self.hname = "IronMan"
        self.rname = "Tony Stark"

    @property
    def hero_name(self):
        return self.hname
    @property
    def reel_name(self):
        return self.rname

data = RDJ()
print(f'The hero name is: {data.hero_name}')
print(f'The reel name is: {data.reel_name}')

我们创建了一个抽象类 Hero 并定义了两个名为hero_namereel_nameusing的抽象属性@abstractproperty。然后,在派生类中RDJ,我们使用@property装饰器来实现它们,这将使它们成为 getter 方法。

然后我们实例化该类并使用该类实例来访问和RDJ的值。hero_namereel_name

The hero name is: IronMan
The reel name is: Tony Stark

如果我们没有将@property装饰器放在类中RDJ,我们就必须调用hero_nameand reel_name

from abc import ABC, abstractproperty

# Abstract class
class Hero(ABC):
    @abstractproperty
    def hero_name(self):
        return self.hname

    @abstractproperty
    def reel_name(self):
        return self.rname

# Derived class
class RDJ(Hero):

    def __init__(self):
        self.hname = "IronMan"
        self.rname = "Tony Stark"

    def hero_name(self):
        return self.hname

    def reel_name(self):
        return self.rname

data = RDJ()
print(f'The hero name is: {data.hero_name()}')
print(f'The reel name is: {data.reel_name()}')

----------
The hero name is: IronMan
The reel name is: Tony Stark

注意:abstractproperty是一个已弃用的类,我们可以使用@propertywith@abstractmethod来定义抽象属性。Pycharm IDE 在使用该类时发出警告abstractproperty

弃用警告

如果我们修改上面的代码,就会像下面这样。

# Abstract class
class Hero(ABC):
    @property
    @abstractmethod
    def hero_name(self):
        return self.hname

    @property
    @abstractmethod
    def reel_name(self):
        return self.rname

只需在抽象类中应用上面代码中所示的修改并运行代码即可。该代码将像之前一样运行,不会出现任何错误。

结论

我们在本文中介绍了抽象类、抽象方法和抽象属性的基础知识。Python 有一个abc模块,提供用于定义抽象基类的基础结构。

ABC模块中的类可abc用于创建抽象类。ABC是一个辅助类,ABCMeta其元类,我们还可以通过传递metaclass关键字并使用 来定义抽象类ABCMeta。这两个类之间的唯一区别是ABCMeta具有附加功能。

创建抽象类后,我们使用@abstractmethodand ( @propertywith @abstractmethod) 装饰器来定义类中的抽象方法和抽象属性。

为了理解该理论,我们在解释的同时编写了示例。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。