在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 相关文章推荐
pyqt和pyside开发图形化界面
Jan 22 Python
Python类定义和类继承详解
May 08 Python
Tensorflow 利用tf.contrib.learn建立输入函数的方法
Feb 08 Python
Python基于递归算法实现的汉诺塔与Fibonacci数列示例
Apr 18 Python
python之文件读取一行一行的方法
Jul 12 Python
pyqt5 实现在别的窗口弹出进度条
Jun 18 Python
python笔记_将循环内容在一行输出的方法
Aug 08 Python
解决python gdal投影坐标系转换的问题
Jan 17 Python
Python实现栈的方法详解【基于数组和单链表两种方法】
Feb 22 Python
Python如何绘制日历图和热力图
Aug 07 Python
Python发送邮件实现基础解析
Aug 14 Python
python pygame 开发五子棋双人对弈
May 02 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编程中字符串处理的5个技巧小结
2007/11/13 PHP
PHP strtr() 函数使用说明
2008/11/21 PHP
php中3种方法统计字符串中每种字符的个数并排序
2012/08/27 PHP
php正则表达式学习笔记
2015/11/13 PHP
php获取目录中所有文件名及判断文件与目录的简单方法
2017/03/04 PHP
jQuery选择没有colspan属性的td的代码
2010/07/06 Javascript
基于jquery的给文章加入关键字链接
2010/10/26 Javascript
javascript异步编程的4种方法
2014/02/19 Javascript
jQuery中innerWidth()方法用法实例
2015/01/19 Javascript
Ext JS动态加载JavaScript创建窗体的方法
2016/06/23 Javascript
妙用Bootstrap的 popover插件实现校验表单提示功能
2016/08/29 Javascript
JavaScript中全选、全不选、反选、无刷新删除、批量删除、即点即改入库(在yii框架中操作)的代码分享
2016/11/01 Javascript
js 性能优化之算法和流程控制
2017/02/15 Javascript
JSON与JS对象的区别与对比
2017/03/01 Javascript
slideToggle+slideup实现手机端折叠菜单效果
2017/05/25 Javascript
js最简单的双向绑定实例讲解
2018/01/02 Javascript
浅谈Node框架接入ELK实践总结
2019/02/22 Javascript
jQuery实现input输入框获取焦点与失去焦点时提示的消失与显示功能示例
2019/05/27 jQuery
解决 window.onload 被覆盖的问题方法
2020/01/14 Javascript
JavaScript实现随机点名程序
2020/03/25 Javascript
js实现tab栏切换效果
2020/08/02 Javascript
详解React路由传参方法汇总记录
2020/11/29 Javascript
JavaScript事件概念详解(区分静态注册和动态注册)
2021/02/05 Javascript
[08:47]2018国际邀请赛 OG战队举杯时刻
2018/08/29 DOTA
[01:18:45]DOTA2-DPC中国联赛 正赛 DLG vs Dragon BO3 第三场2月1日
2021/03/11 DOTA
浅析HTML5的WebSocket与服务器推送事件
2016/02/19 HTML / CSS
Agoda香港:全球特价酒店预订
2017/05/07 全球购物
七一党建活动方案
2014/01/28 职场文书
食品安全工作实施方案
2014/03/26 职场文书
《小鹰学飞》教学反思
2014/04/23 职场文书
好的旅游活动方案
2014/08/19 职场文书
群教个人对照检查材料
2014/08/20 职场文书
接收函格式
2015/01/30 职场文书
python3操作redis实现List列表实例
2021/08/04 Python
三种方式清除vue路由跳转router-link的历史记录
2022/04/10 Vue.js
Android开发之底部导航栏的快速实现
2022/04/28 Java/Android