在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转码问题的解决方法
Oct 07 Python
python发送邮件接收邮件示例分享
Jan 21 Python
使用PyInstaller将Python程序文件转换为可执行程序文件
Jul 08 Python
python paramiko模块学习分享
Aug 23 Python
Python带动态参数功能的sqlite工具类
May 26 Python
python+selenium实现自动抢票功能实例代码
Nov 23 Python
python flask搭建web应用教程
Nov 19 Python
Python matplotlib画曲线例题解析
Feb 07 Python
python实现简单井字棋小游戏
Mar 05 Python
Python figure参数及subplot子图绘制代码
Apr 18 Python
公认8个效率最高的爬虫框架
Jul 28 Python
PyCharm 安装与使用配置教程(windows,mac通用)
May 12 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
用js进行url编码后用php反解以及用php实现js的escape功能函数总结
2010/02/08 PHP
rephactor 优秀的PHP的重构工具
2011/06/09 PHP
分享常见的几种页面静态化的方法
2015/01/08 PHP
客户端脚本中常常出现的一些问题和调试技巧
2007/01/09 Javascript
把textarea中字符串里含有的回车换行替换成&amp;lt;br&amp;gt;的javascript代码
2007/04/20 Javascript
JavaScript 设计模式之组合模式解析
2010/04/09 Javascript
select 控制网页内容隐藏于显示的实现代码
2010/05/25 Javascript
说说JSON和JSONP 也许你会豁然开朗
2012/09/02 Javascript
JS获取浏览器版本及名称实现函数
2013/04/02 Javascript
JQuery操作单选按钮以及复选按钮示例
2013/09/23 Javascript
jquery实现适用于门户站的导航下拉菜单效果代码
2015/08/24 Javascript
jQuery插件实现文字无缝向上滚动效果代码
2016/02/25 Javascript
深入理解jQuery中的事件冒泡
2016/05/24 Javascript
jQuery实现动态文字搜索功能
2017/01/05 Javascript
浅谈js中的this问题
2017/08/31 Javascript
jQuery实现鼠标移入移出事件切换功能示例
2018/09/06 jQuery
小程序封装路由文件和路由方法(5种全解析)
2019/05/26 Javascript
js事件触发操作实例分析
2019/06/21 Javascript
JS实现放烟花效果
2020/03/10 Javascript
微信小程序弹窗禁止页面滚动的实现代码
2020/12/30 Javascript
[11:42]2018DOTA2国际邀请赛寻真——OG卷土重来
2018/08/17 DOTA
[50:54]完美世界DOTA2联赛 GXR vs IO 第三场 11.07
2020/11/10 DOTA
python3中eval函数用法使用简介
2019/08/02 Python
对Python 中矩阵或者数组相减的法则详解
2019/08/26 Python
Transpose 数组行列转置的限制方式
2020/02/11 Python
解决flask接口返回的内容中文乱码的问题
2020/04/03 Python
Django中的DateTimeField和DateField实现
2021/02/24 Python
localStorage、sessionStorage使用总结
2017/11/17 HTML / CSS
跑步爱好者一站式服务网站:Jack Rabbit
2016/09/01 全球购物
乌克兰品牌化妆品和香水在线商店:Bomond
2020/01/14 全球购物
中科方德软件测试面试题
2016/04/21 面试题
俞敏洪一分钟演讲稿
2014/08/26 职场文书
2015年事业单位办公室文员工作总结
2015/04/24 职场文书
2015年销售助理工作总结
2015/05/11 职场文书
证婚人婚礼致辞
2015/07/28 职场文书
入党申请书怎么写?
2019/06/11 职场文书