在这篇文章中,我们将为您详细介绍为什么在Python中使用抽象基类?的内容,并且讨论关于python抽象基类的作用的相关问题。此外,我们还会涉及一些关于c++——为什么要使用多态?什么是虚函数、抽象基
在这篇文章中,我们将为您详细介绍为什么在 Python 中使用抽象基类?的内容,并且讨论关于python抽象基类的作用的相关问题。此外,我们还会涉及一些关于c++ ——为什么要使用多态?什么是虚函数、抽象基类?、C++ 函数继承详解:如何定义和使用抽象基类?、Python abc—抽象基类、python – 为什么在字符串连接中使用os.path.join?的知识,以帮助您更全面地了解这个主题。
本文目录一览:- 为什么在 Python 中使用抽象基类?(python抽象基类的作用)
- c++ ——为什么要使用多态?什么是虚函数、抽象基类?
- C++ 函数继承详解:如何定义和使用抽象基类?
- Python abc—抽象基类
- python – 为什么在字符串连接中使用os.path.join?
为什么在 Python 中使用抽象基类?(python抽象基类的作用)
因为我习惯了 Python 中鸭子类型的旧方法,所以我无法理解对
ABC(抽象基类)的需求。关于如何使用它们的帮助很好。
我试图阅读PEP中的基本原理,但它超出了我的想象。如果我正在寻找一个可变序列容器,我会检查__setitem__
,或者更有可能尝试使用它(EAFP)。我还没有遇到过数字模块的实际用途,它确实使用了 ABC,但这是我必须理解的最接近的。
谁能给我解释一下原因吗?
c++ ——为什么要使用多态?什么是虚函数、抽象基类?
多态可分为静态多态和动态多态
- 静态多态就是在系统编译期间就可以确定程序执行到这里将要执行哪个函数,比如函数的重载。
- 动态多态则是利用虚函数实现了运行时的多态,也就是说在系统编译的时候并不知道程序将要调用哪一个函数,只有在运行到这里的时候才能确定接下来会跳转到哪一个函数的栈帧。
虚函数:
在基类中声明该函数是虚拟的(在函数之前加virtual关键字),然后在子类中正式的定义(子类中的该函数的函数名,返回值,函数参数个数,参数类型,全都与基类的所声明的虚函数相同,此时才能称为重写,才符合虚函数,否则就是函数的重载),再定义一个指向基类对象的指针,然后使该指针指向由该基类派生的子类对象,再然后用这个指针来调用改虚函数,就能实现动态多态。
下面以"计算器"举例说明:
- 不使用多态的版本如下:
class Caculator
{
public:
int getResult(char fun){
if(fun == ''+'') return a+b;
else if(fun == ''-'') return a-b;
else if(fun == ''*'') return a*b;
//增加计算方式时 需要手动增删源代码
}
int a;
int b;
};
int main()
{
char fun;
Caculator x;
x.a=5;
x.b=10;
cin >> fun;
cout << x.getResult(fun);
}
- 使用多态的版本如下:
class Caculator//父类计算器
{
public:
virtual int getResult(){
return 0;
}
int a;
int b;
};
//子类:加法器
class Add : public Caculator{
public:
int getResult(){
return a+b;
}
};
//此处省略减法器、乘法器等。
int main(){
Caculator* c = new Add;
c->a=1;
c->b=2;
cout << c->getResult() << endl;
return 0;
}
可以见得,使用多态的优点有:
1.组织结构清晰
2.可读性强
3.易于扩展,可维护性高 (tips:在实际开发中,提倡扩展而不提倡修改,也正是多态的优势所在)
在多态中,父类中的虚函数实现是毫无意义的,主要都由子类编写对应函数。
所以可以将父类中的虚函数编写为纯虚函数。
纯虚函数:
- 意义:告诉用户这个函数是没有实际意义的。
- 用法:在函数体的位置书写=0; 例如:
class A{
public:
...
virtual void function(){
...}
}
抽象基类
- 定义:含有纯虚函数的类是抽象基类。
- 解释:①抽象基类负责定义接口,而后续的其他类可以覆盖该接口。②我们不能直接创建一个抽象基类的对象(即不能实例化),并且抽象基类的派生类中必须对抽象基类中的纯虚函数进行重写。
C++ 函数继承详解:如何定义和使用抽象基类?
函数继承允许派生类复用基类的函数定义,通过以下步骤实现:定义抽象基类,包含纯虚函数。在派生类中使用 override 关键字继承并实现基类的函数。实战案例:创建抽象基类 shape,派生类 circle 和 rectangle 计算不同形状的面积。
C++ 函数继承详解:定义和使用抽象基类
什么是函数继承?
函数继承是一种 C++ 特性,它允许派生类继承基类的函数定义,从而在子类中复用基类的功能。
立即学习“C++免费学习笔记(深入)”;
定义抽象基类
一个抽象基类是一个不打算被实例化的基类,它只作为其他类的基类。它包含纯虚函数(即没有函数体的函数),这些函数必须在派生类中被重写。要声明一个抽象基类,可以使用 virtual 和 = 0,例如:
class Shape { public: virtual double area() const = 0; };
派生类中的函数继承
派生类可以继承抽象基类的函数定义,方法是使用 override 关键字并提供函数的实现。例如:
class Circle : public Shape { public: override double area() const { return M_PI * radius * radius; } private: double radius; };
实战案例:形状面积计算
让我们以计算形状面积为例进行一个实战演示。我们创建一个 Shape 抽象基类,并创建 Circle 和 Rectangle 派生类来计算圆和矩形的面积:
#include <iostream> #include <cmath> using namespace std; class Shape { public: virtual double area() const = 0; }; class Circle : public Shape { public: Circle(double radius) : radius(radius) {} override double area() const { return M_PI * radius * radius; } private: double radius; }; class Rectangle : public Shape { public: Rectangle(double width, double height) : width(width), height(height) {} override double area() const { return width * height; } private: double width; double height; }; int main() { Circle circle(5); cout << "Circle area: " << circle.area() << endl; Rectangle rectangle(3, 4); cout << "Rectangle area: " << rectangle.area() << endl; return 0; }
运行输出:
Circle area: 78.5398 Rectangle area: 12
以上就是C++ 函数继承详解:如何定义和使用抽象基类?的详细内容,更多请关注php中文网其它相关文章!
Python abc—抽象基类
该模块提供了在Python中定义抽象基类(ABC - Abstract Base Class)的基础结构,参考PEP 3119;至于为何将其添加到 Python,也可以看看PEP 3141和numbers
模块有关基于ABC的 numbers 的类层次结构的模块。
容器collections
模块具有一些衍生自ABC的具体类。当然,这些可以进一步继承衍生。此外, collections.abc
子模块具有一些 ABC,可用于测试:类或实例是否提供特定的接口,例如,是否可哈希或是否为映射。
此模块提供ABCMeta
用于定义ABC 的元类和帮助程序类,ABC
以通过继承来替代地定义ABC:
classabc.
`ABC
具有ABCMeta
作为其元类的帮助程序类。使用此类,可以通过ABC
避免有时混淆元数据用法的简单派生来创建抽象基类,例如:
from abc import ABC
class MyABC(ABC):
pass
请注意,类型ABC
为still ABCMeta
,因此从继承继承ABC
需要有关元类使用的常规预防措施,因为多重继承可能会导致元类冲突。也可以通过传递 metaclass 关键字并ABCMeta
直接使用来定义抽象基类,例如:
from abc import ABCMeta
class MyABC(metaclass=ABCMeta):
pass
3.4版的新功能。
class abc.
`ABCMeta`
用于定义抽象基类(ABC)的元类。
使用此元类创建一个ABC。ABC可以直接子类化,然后充当混合类。您还可以将不相关的具体类(甚至是内置类)和不相关的ABC注册为“虚拟子类” –内置issubclass()
函数会将它们及其后代视为注册ABC的子类,但是注册ABC不会显示在其 MRO(方法解决顺序)中,由注册ABC定义的方法实现也将不可调用(甚至不能通过调用 super()
)。1个
使用元类创建的类ABCMeta
具有以下方法:
register
(_subclass_)
将__subclass__注册为该ABC的“虚拟子类”。例如:
from abc import ABC
class MyABC(ABC):
pass
MyABC.register(tuple)
assert issubclass(tuple, MyABC)
assert isinstance((), MyABC)
在版本3.3中更改:返回注册的子类,以允许用作类装饰器。
在版本3.4中更改:要检测对的调用register()
,可以使用该 get_cache_token()
功能。
您还可以在抽象基类中重写此方法:
__subclasshook__
(_子类_)
(必须定义为类方法。)
检查_子类_是否被视为此ABC的子类。这意味着您可以自定义issubclass
进一步的行为,而无需调用register()
要考虑为ABC的子类的每个类。(此类方法是从__subclasscheck__()
ABC 的方法中调用的。)
这个方法应该返回True
,False
或NotImplemented
。如果返回True
,则将该_子类_视为此ABC的子类。如果返回False
,则即使该子类通常是一个_子类,_也不会将该_子类_视为该ABC的子类。如果返回 NotImplemented
,则使用常规机制继续子类检查。
为了演示这些概念,请看以下示例ABC定义:
class Foo:
def __getitem__(self, index):
...
def __len__(self):
...
def get_iterator(self):
return iter(self)
class MyIterable(ABC):
@abstractmethod
def __iter__(self):
while False:
yield None
def get_iterator(self):
return self.__iter__()
@classmethod
def __subclasshook__(cls, C):
if cls is MyIterable:
if any("__iter__" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
MyIterable.register(Foo)
ABC MyIterable
将标准可迭代方法定义 __iter__()
为抽象方法。此处给出的实现仍可以从子类中调用。该get_iterator()
方法也是MyIterable
抽象基类的一部分,但是在非抽象派生类中不必重写此方法~~~~。
__subclasshook__()
此处定义的类方法表示,任何__iter__()
在其类__dict__
(或通过__mro__
列表访问的基类之一)中具有方法的 类也被视为类MyIterable
。
最后,即使没有定义方法,最后一行仍是Foo
的虚拟子类(它使用按照和 定义的旧式可迭代协议)。请注意,这不能 作为的方法使用,因此是单独提供的。MyIterable
__iter__()
__len__()
__getitem__()
get_iterator
`Foo`
该abc
模块还提供以下装饰器:
@
`abc.`abstractmethod
[](https://docs.python.org/3/lib... "此定义的永久链接")
装饰器,指示抽象方法。
使用此装饰器要求该类的元类是ABCMeta
或从其派生的。ABCMeta
除非实例化了其所有抽象方法和属性,否则无法实例化具有派生自其的元类的类 。可以使用任何正常的“超级”调用机制来调用抽象方法。 abstractmethod()
可以用来声明属性和描述符的抽象方法。
不支持将动态方法添加到类,或在创建方法或类后尝试修改其抽象状态。将abstractmethod()
仅影响使用常规继承派生的子类; 使用ABC register()
方法注册的“虚拟子类” 不受影响。
当abstractmethod()
与其他方法描述符结合使用时,应将其用作最里面的装饰器,如以下用法示例所示:~~~~
class C(ABC):
@abstractmethod
def my_abstract_method(self, ...):
...
@classmethod
@abstractmethod
def my_abstract_classmethod(cls, ...):
...
@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):
...
@property
@abstractmethod
def my_abstract_property(self):
...
@my_abstract_property.setter
@abstractmethod
def my_abstract_property(self, val):
...
@abstractmethod
def _get_x(self):
...
@abstractmethod
def _set_x(self, val):
...
x = property(_get_x, _set_x)
为了正确地与抽象基类机制互操作,描述符必须使用标识自己为抽象 __isabstractmethod__
。通常,True
如果用于构成描述符的任何方法都是抽象的,则此属性应为。例如,Python的内置功能property
等效于:
class Descriptor:
...
@property
def __isabstractmethod__(self):
return any(getattr(f, ''__isabstractmethod__'', False) for f in (self._fget, self._fset, self._fdel))
注意
与Java抽象方法不同,这些抽象方法可能具有实现(Java新版也有接口默认实现)。可以通过super()
覆盖它的类中的机制来调用此实现。在使用协作式多重继承的框架中,这可用作超级调用的端点。
该abc
模块还支持以下旧式装饰器:
@
`abc.`abstractclassmethod
[](https://docs.python.org/3/lib... "此定义的永久链接")
3.2版中的新功能。
自从3.3版本不推荐使用:现在可以使用classmethod
用 abstractmethod()
,使这个装饰是多余的。
内置的子类classmethod()
,指示抽象的类方法。否则它类似于abstractmethod()
。
不建议使用这种特殊情况,因为classmethod()
现在将装饰器应用于抽象方法时,可以正确地将其标识为抽象:
class C(ABC):
@classmethod
@abstractmethod
def my_abstract_classmethod(cls, ...):
...
@
`abc.`abstractstaticmethod
3.2版中的新功能。
自从3.3版本不推荐使用:现在可以使用staticmethod
用 abstractmethod()
,使这个装饰是多余的。
内置的子类staticmethod()
,指示抽象的静态方法。否则它类似于abstractmethod()
。
不建议使用这种特殊情况,因为staticmethod()
现在将装饰器应用于抽象方法时,可以正确地将其标识为抽象:
class C(ABC):
@staticmethod
@abstractmethod
def my\_abstract\_staticmethod(...):
...
@abc.abstractproperty
自从3.3版本不推荐使用:现在可以使用property
,property.getter()
, property.setter()
和property.deleter()
用 abstractmethod()
,使这个装饰是多余的。
内置的子类property()
,指示抽象属性。
不建议使用这种特殊情况,因为property()
现在将装饰器应用于抽象方法时,可以正确地将其标识为抽象:
class C(ABC):
@property
@abstractmethod
def my_abstract_property(self):
...
上面的示例定义了一个只读属性;您还可以通过适当地将一个或多个基础方法标记为抽象来定义读写抽象属性:
class C(ABC):
@property
def x(self):
...
@x.setter
@abstractmethod
def x(self, val):
...
如果只有某些组件是抽象的,则仅需要更新那些组件即可在子类中创建具体属性:
class D(C):
@C.x.setter
def x(self, val):
...
该abc
模块还提供以下功能:
abc.get_cache_token()
返回当前抽象基类缓存令牌。
令牌是一个不透明的对象(支持相等性测试),用于标识虚拟子类的抽象基类缓存的当前版本。令牌随着ABCMeta.register()
在任何ABC上的每次调用而改变。
3.4版的新功能。
脚注
1个
C++程序员应注意,Python的虚拟基类概念与C++不同。
python – 为什么在字符串连接中使用os.path.join?
我主要使用VBScript,所以我不明白这个功能的意义.
解决方法
编写文件路径操作一次,它可以在许多不同的平台上免费使用.分隔字符被抽象化,使您的工作更轻松.
聪明
您不再需要担心该目录路径是否具有trailing slash or not. os.path.join将在需要时添加它.
明确
使用os.path.join可以让其他人阅读您正在使用文件路径的代码.人们可以快速扫描代码并发现它本质上是一个文件路径.如果您决定自己构建它,您可能会让读者不要发现代码的实际问题:“嗯,一些字符串concats,一个替换.这是一个文件路径还是什么?Gah!为什么他没有使用os.path .加入?”
总结
以上是小编为你收集整理的python – 为什么在字符串连接中使用os.path.join?全部内容。
如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。
关于为什么在 Python 中使用抽象基类?和python抽象基类的作用的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于c++ ——为什么要使用多态?什么是虚函数、抽象基类?、C++ 函数继承详解:如何定义和使用抽象基类?、Python abc—抽象基类、python – 为什么在字符串连接中使用os.path.join?的相关信息,请在本站寻找。
本文标签: