在Python中定义和使用抽象类的方法


Posted in Python onJune 30, 2016

像java一样python也可以定义一个抽象类。

在讲抽象类之前,先说下抽象方法的实现。

抽象方法是基类中定义的方法,但却没有任何实现。在java中,可以把方法申明成一个接口。而在python中实现一个抽象方法的简单的方法是:

class Sheep(object):
  def get_size(self):
    raise NotImplementedError

任何从Sheep继承下来的子类必须实现get_size方法。否则就会产生一个错误。但这种实现方法有个缺点。定义的子类只有调用那个方法时才会抛错。这里有个简单方法可以在类被实例化后触发它。使用python提供的abc模块。

import abc
class Sheep(object):
  __metaclass__ = abc.ABCMeta
  
  @abc.absractmethod
  def get_size(self):
    return

这里实例化Sheep类或任意从其继承的子类(未实现get_size)时候都会抛出异常。

因此,通过定义抽象类,可以定义子类的共同method(强制其实现)。

如何使用抽象类

import abc 

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def load(self, input):
    return 

  @abc.abstractmethod
  def save(self, output, data):
    return

通过ABCMeta元类来创建一个抽象类, 使用abstractmethod装饰器来表明抽象方法

注册具体类

class B(object):
  
  def load(self, input):
    return input.read()

  def save(self, output, data):
    return output.write(data)

A.register(B)

if __name__ == '__main__':
  print issubclass(B, A)   # print True
  print isinstance(B(), A)  # print True

从抽象类注册一个具体的类

子类化实现

class C(A):

  def load(self, input):
    return input.read()

  def save(self, output, data):
    return output.write(data)
    
if __name__ == '__main__':
  print issubclass(C, A)   # print True
  print isinstance(C(), A)  # print True

可以使用继承抽象类的方法来实现具体类这样可以避免使用register. 但是副作用是可以通过基类找出所有的具体类

for sc in A.__subclasses__():
  print sc.__name__

# print C

如果使用继承的方式会找出所有的具体类,如果使用register的方式则不会被找出

使用__subclasshook__

使用__subclasshook__后只要具体类定义了与抽象类相同的方法就认为是他的子类

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def say(self):
    return 'say yeah'

  @classmethod
  def __subclasshook__(cls, C):
    if cls is A:
      if any("say" in B.__dict__ for B in C.__mro__):
        return True
    return NotTmplementd

class B(object):
  def say(self):
    return 'hello'

print issubclass(B, A)   # True
print isinstance(B(), A)  # True
print B.__dict__      # {'say': <function say at 0x7f...>, ...}
print A.__subclasshook__(B) # True

不完整的实现

class D(A):
  def save(self, output, data):
    return output.write(data)

if __name__ == '__main__':
  print issubclass(D, A)   # print True
  print isinstance(D(), A)  # raise TypeError

如果构建不完整的具体类会抛出D不能实例化抽象类和抽象方法

具体类中使用抽象基类

import abc 
from cStringIO import StringIO

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def retrieve_values(self, input):
    pirnt 'base class reading data'
    return input.read()


class B(A):

  def retrieve_values(self, input):
    base_data = super(B, self).retrieve_values(input)
    print 'subclass sorting data'
    response = sorted(base_data.splitlines())
    return response

input = StringIO("""line one
line two
line three
""")

reader = B()
print reader.retrieve_values(input)

打印结果

base class reading data
subclass sorting data
['line one', 'line two', 'line three']

可以使用super来重用抽象基类中的罗辑, 但会迫使子类提供覆盖方法.

抽象属性

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractproperty
  def value(self):
    return 'should never get here.'

class B(A):
  
  @property
  def value(self):
    return 'concrete property.'

try:
  a = A()
  print 'A.value', a.value
except Exception, err:
  print 'Error: ', str(err)

b = B()
print 'B.value', b.value

打印结果,A不能被实例化,因为只有一个抽象的property getter method.

Error: ...
print concrete property

定义抽象的读写属性

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  def value_getter(self):
    return 'Should never see this.'

  def value_setter(self, value):
    return 

  value = abc.abstractproperty(value_getter, value_setter)

class B(A):
  
  @abc.abstractproperty
  def value(self):
    return 'read-only'

class C(A):
  _value = 'default value'

  def value_getter(self):
    return self._value

  def value_setter(self, value):
    self._value = value

  value = property(value_getter, value_setter)

try:
  a = A()
  print a.value
except Exception, err:
  print str(err)

try:
  b = B()
  print b.value
except Exception, err:
  print str(err)

c = C()
print c.value

c.value = 'hello'
print c.value

打印结果, 定义具体类的property时必须与抽象的abstract property相同。如果只覆盖其中一个将不会工作.

error: ...
error: ...
print 'default value'
print 'hello'

使用装饰器语法来实现读写的抽象属性, 读和写的方法应该相同.

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractproperty
  def value(self):
    return 'should never see this.'

  @value.setter
  def value(self, _value):
    return 

class B(A):
  _value = 'default'

  @property
  def value(self):
    return self._value

  @value.setter
  def value(self, _value):
    self._value = _value

b = B()
print b.value    # print 'default'

b.value = 'hello'
print b.value    # print 'hello'
Python 相关文章推荐
Python中运行并行任务技巧
Feb 26 Python
Django实现图片文字同时提交的方法
May 26 Python
Python实现破解猜数游戏算法示例
Sep 25 Python
python+pyqt实现12306图片验证效果
Oct 25 Python
django2 快速安装指南分享
Jan 05 Python
Python使用Matplotlib模块时坐标轴标题中文及各种特殊符号显示方法
May 04 Python
详解Python中字符串前“b”,“r”,“u”,“f”的作用
Dec 18 Python
深入浅析python的第三方库pandas
Feb 13 Python
python列表的逆序遍历实现
Apr 20 Python
Python退出时强制运行一段代码的实现方法
Apr 29 Python
使用PyQt的QLabel组件实现选定目标框功能的方法示例
May 19 Python
Python如何使用循环结构和分支结构
Apr 13 Python
Python中functools模块的常用函数解析
Jun 30 #Python
深入浅析Python中join 和 split详解(推荐)
Jun 30 #Python
Python列出一个文件夹及其子目录的所有文件
Jun 30 #Python
django之常用命令详解
Jun 30 #Python
全面了解Python环境配置及项目建立
Jun 30 #Python
浅谈Python 集合(set)类型的操作——并交差
Jun 30 #Python
python dict.get()和dict['key']的区别详解
Jun 30 #Python
You might like
最新的php 文件上传模型,支持多文件上传
2009/08/13 PHP
php在文件指定行中写入代码的方法
2012/05/23 PHP
php编写简单的文章发布程序
2015/06/18 PHP
PHP-CGI远程代码执行漏洞分析与防范
2017/05/07 PHP
PHP获取HTTP body内容的方法
2018/12/31 PHP
详细讲解JS节点知识
2010/01/31 Javascript
仿微博字符限制效果实现代码
2012/04/20 Javascript
js代码实现的加入收藏效果并兼容主流浏览器
2014/06/23 Javascript
TypeScript 学习笔记之基本类型
2015/06/19 Javascript
jQuery基于muipicker实现仿ios时间选择
2016/02/22 Javascript
基于Bootstrap实现tab标签切换效果
2020/04/15 Javascript
基于vue.js实现侧边菜单栏
2017/03/20 Javascript
微信小程序 swiper组件构建轮播图的实例
2017/09/20 Javascript
详解vue.js数据传递以及数据分发slot
2018/01/20 Javascript
创建Vue项目以及引入Iview的方法示例
2018/12/03 Javascript
vue+django实现一对一聊天功能的实例代码
2019/07/17 Javascript
Python 结巴分词实现关键词抽取分析
2017/10/21 Python
Python中的Numpy矩阵操作
2018/08/12 Python
Python实现微信消息防撤回功能的实例代码
2019/04/29 Python
浅析Windows 嵌入python解释器的过程
2019/07/26 Python
详解numpy.meshgrid()方法使用
2019/08/01 Python
python 实现二维列表转置
2019/12/02 Python
python torch.utils.data.DataLoader使用方法
2020/04/02 Python
Flask缓存静态文件的具体方法
2020/08/02 Python
Python Serial串口基本操作(收发数据)
2020/11/06 Python
顶丰TOPPIK台湾官网:增发纤维假发,告别秃发困扰
2018/06/13 全球购物
澳大利亚有机化妆品网上商店:The Well Store
2020/02/20 全球购物
托管代码(Managed Code)和非托管代码(Unmanaged Code)有什么区别
2014/09/29 面试题
大一学生的职业生涯规划书范文
2014/01/19 职场文书
教师党员公开承诺书
2014/03/25 职场文书
幼儿评语大全
2014/04/30 职场文书
2014光棍节单身联谊活动策划书
2014/10/10 职场文书
离婚答辩状范文
2015/05/22 职场文书
幼儿园音乐教学反思
2016/02/18 职场文书
范文之农村基层党建工作报告
2019/10/24 职场文书
Laravel中获取IP的真实地理位置
2021/04/01 PHP