1. 程式人生 > 實用技巧 >python 抽象基類

python 抽象基類

#抽象基類是一個分配身份的機制
# 宣告虛擬子類 ABCMeta抽象基類的元類

import abc
class AbstractDict(metaclass=abc.ABCMeta):
def foo(self):
return None

ab = AbstractDict.register(dict)
print(ab)
# print(ab.foo())

print(isinstance({},AbstractDict))
print(issubclass(dict,AbstractDict))

# 宣告虛擬子類的原因
# 抽象基類可以提供一個非常好的擴充套件機制,示例如下:

class MySequence(metaclass=abc.ABCMeta):

pass

MySequence.register(list)
MySequence.register(tuple)

print(isinstance([],MySequence))
print(isinstance((),MySequence))
print(isinstance(object(),MySequence))

class CustomListLikeClass(object):
pass

MySequence.register(CustomListLikeClass)

print('object*************************')
print(isinstance(CustomListLikeClass(),MySequence))

#python3.3以來register方法可以作為裝飾器,因為register方法返回類,3.3版本之前返回None,因此不能作為裝飾器
@MySequence.register
class CustomListLikeClass(object):
pass


class AbstractDuck(metaclass=abc.ABCMeta):
"""該抽象基類宣告,任何帶有quack方法的類都被認為是他的子類"""
@classmethod
def __subclasshook__(cls,other):

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

return callable(quack)


class Duck(object):

def quack(self):
pass

print(issubclass(Duck,AbstractDuck))

class NotDuck(object):
quack = 'foo'

AbstractDuck.register(NotDuck) #當__subclasshook__被定義時,優先順序大於register
print(issubclass(NotDuck,AbstractDuck))


# 以上展示抽象基類是如何使一個類能夠宣告它自身可以通過型別檢查測試

# 其他現有方法#######################################################

# 1.使用NotImplementedError

from datetime import datetime

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()

# 2.使用元類

class TaskMeta(type):

def __new__(cls,name,bases,attrs):

if attrs.pop('abstract',False):

return super(TaskMeta, cls).__new__(cls,name,bases,attrs)

new_class = super(TaskMeta, cls).__new__(cls,name,bases,attrs)

if not hasattr(new_class,'_run') or not callable(new_class._run):
raise TypeError('Task subclass must define _run method')

return new_class

class Task1(metaclass=TaskMeta):
abstract = True
pass

Task1()

# 抽象基類的價值
class Task3(metaclass=abc.ABCMeta):

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

@abc.abstractmethod
def _run(self):
pass


class SubTask(Task3):
pass

# 無法例項化
# SubTask()

class OtherTask(Task3):

def _run(self):

return 2

OtherTask().run()

# 抽象屬性
class AbstractClass(metaclass=abc.ABCMeta):

@property
@abc.abstractproperty
def foo(self):
pass


# 抽象類或靜態方法
class AbstractClass1(metaclass=abc.ABCMeta):
@classmethod
@abc.abstractmethod
def foo(cls):
return 42

class SubC(AbstractClass1):
pass

print(SubC.foo())
# SubC不能例項化

# 內建抽象基類
from collections.abc import *
Callable(__call__)
Container(__contains__)
Hashable(__hash__)
Iterable(__iter__)
Sized(__len__)