python抽象基类的作用_Python——抽象基类

Python的抽象基类(ABC)提供声明抽象方法的机制,要求子类实现关键功能。ABCMeta元类用于创建抽象基类,register方法注册子类,__subclasshook__定义子类检测。未实现抽象方法的子类无法实例化,抽象属性确保特定方法的实现。ABC在对象验证和协议定义中起到关键作用。
摘要由CSDN通过智能技术生成

在处理编程和对象时,强调构成问题而不是身份问题,强调hasattr函数而不是isinstance函数。抽象基类是一个分配身份的机制。抽象基类也提供了一个标明抽象方法的机制,就是要求其他实现提供关键性功能,这些功能是在基类中实现中不主动提供的功能。

抽象基类提供了声明一个类是另一个类的派生类的机制(无论它是否是另一个类的派生类),该机制没有影响实际的对象继承关系或是改变方法解析顺序。

抽象基类提供了一种要求子类实现指定协议的方式。如果一个抽象基类要求实现指定方法,而子类没有实现这个方法,然后当试图创建子类时会抛出错误。

abc模块是表示抽象基类的模块,它提供一个名为ABCMeta的元类,任何抽象基类必须使用ABCMeta元类。

声明虚拟子类

>>>import abc

>>>class AbstractDict(metaclass = ABCMeta):

def foo(self):

return None

>>>AbstractDict.register(dict)

>>>{}.foo()

Traceback

...

...AttributeError:'dict' object has no attribute 'foo'

dict的方法解析并没有发生改变

>>>isinstance({}, AbstractDict)

True

>>>isinstance(AbstractDict, {})

False

register方法是ABCMeta元类的类所提供的方法,用来注册应该被注册为ABCMeta子类的新类。

>>>@AbstractDict.register

...class DictLikeAbstract(object):

... pass

>>>issubclass(DictLikeAbstract, AbstractDict)

>>>True

__subclasshook__:此方法必须定义为一个类方法,并且使用@classmethod装饰器定义,接受一个额外的位置参数是被测试的类

>>> import abc

>>> class AbstractDuck(object):

__metaclass__ = abc.ABCMeta

@classmethod

def __subclasshook__(cls, other):

quack = getattr(other, 'quack', None)

return callable(quack)

>>> class Duck(object):

def quack(self):

pass

>>> class NotDuck(object):

quack = 'foo'

>>> issubclass(Duck, AbstractDuck)

True

>>> issubclass(NotDuck, AbstractDuck)

False

>>> AbstractDuck.register(NotDuck)

>>> issubclass(NotDuck, AbstractDuck)

False

如果子类中有可调用的quack方法则是AbstractDuck的子类。__subclasshook__方法被定义时优于register方法。

>>> class Task(object):

def __init__(self):

self.runs = []

def run(self):

start = datetime.now()

result = self._run()

end = datetime.now()

self.runs.append({

'start': start,

'end': end,

'result': result,

})

return result

def _run(self):

raise NotImplementedError('Task subclasses must define a _run method.')

>>> t = Task()

>>> t.run()

Traceback (most recent call last):

File "", line 1, in

t.run()

File "", line 6, in run

result = self._run()

File "", line 15, in _run

raise NotImplementedError('Task subclasses must define a _run method.')

NotImplementedError: Task subclasses must define a _run method.

Task提供一个shell方法_run,任何未能重写_run的子类大都会引发NotImplementedError

>>> class SubTask(Task):

def _run(self):

return 2+2

>>> subtask = SubTask()

>>> subtask.run()

4

抽象基类可以被明确提出作为满足特定需求的解决方案,依据这一概念,理想情况下使用抽象基类后应该仅有一种实现这种特定需求的正确方法。

抽象属性

>>> class AbstractClass(object):

__metaclass__ = abc.ABCMeta

@abc.abstractproperty

def foo(self):

pass

>>> class InvalidChild(AbstractClass):

pass

>>> ic = InvalidChild()

Traceback (most recent call last):

File "", line 1, in

ic = InvalidChild()

TypeError: Can't instantiate abstract class InvalidChild with abstract methods foo

>>> class ValidChild(AbstractClass):

def foo(self):

return 'foo'

>>> vc = ValidChild()

>>> vc.foo()

'foo'

>>> InvalidChild.foo()

Traceback (most recent call last):

File "", line 1, in

InvalidChild.foo()

TypeError: 'abstractproperty' object is not callable

重写抽象方法的子类才能被实例化

抽象类或静态方法

class AbstractClass(metaclass=abc.ABCMeta):

@classmethod

@abc.abstractmethod

def foo(cls):

return 42

>>>class InvalidChild(AbstractClass):

pass

>>>ic = InvalidChild()

Traceback

....

TypeError:Can't instantiate abstract class....

抽象方法本身能够被直接调用,且不会引发任何错误

>>>InvalidChild.foo()

42

抽象基类最重要的作用是提供了一个正式和动态的方式来回答这个问题,‘你正在获取的对象是你认为的类型吗’,它可以克服一些仅仅检测特定属性是否存在或仅仅检测是否为特定类这两种方法的缺点。

《Python高级编程》——读书笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值