在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通过yield实现数组全排列的方法
Mar 18 Python
Python中的模块导入和读取键盘输入的方法
Oct 16 Python
Python实现爬虫设置代理IP和伪装成浏览器的方法分享
May 07 Python
python实现比较文件内容异同
Jun 22 Python
详解Django中间件的5种自定义方法
Jul 26 Python
CentOS下Python3的安装及创建虚拟环境的方法
Nov 28 Python
Python中使用遍历在列表中添加字典遇到的坑
Feb 27 Python
Python实现的合并两个有序数组算法示例
Mar 04 Python
windows下Python安装、使用教程和Notepad++的使用教程
Oct 06 Python
Python生成词云的实现代码
Jan 14 Python
Python基于numpy模块实现回归预测
May 14 Python
如何在 Matplotlib 中更改绘图背景的实现
Nov 26 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中通过curl检测页面是否被百度收录
2013/09/27 PHP
PHP实现的一致性Hash算法详解【分布式算法】
2018/03/31 PHP
基于jquery的兼容各种浏览器的iframe自适应高度的脚本
2010/08/13 Javascript
js如何获取object类型里的键值
2014/02/18 Javascript
JS实现FLASH幻灯片图片切换效果的方法
2015/03/04 Javascript
JavaScript实现为指定对象添加多个事件处理程序的方法
2015/04/17 Javascript
Extjs 点击复选框在表格中增加相关信息行
2016/07/12 Javascript
JavaScript仿微博输入框效果(案例分析)
2016/12/06 Javascript
详解从Node.js的child_process模块来学习父子进程之间的通信
2017/03/27 Javascript
ionic2屏幕适配实现适配手机、平板等设备的示例代码
2017/08/11 Javascript
vue.js todolist实现代码
2017/10/29 Javascript
ztree实现左边动态生成树右边为内容详情功能
2017/11/03 Javascript
微信小程序自定义导航栏实例代码
2019/04/05 Javascript
nodejs中实现用户注册路由功能
2019/05/20 NodeJs
echarts统计x轴区间的数值实例代码详解
2019/07/07 Javascript
vue实现修改图片后实时更新
2019/11/14 Javascript
Python的高级Git库 Gittle
2014/09/22 Python
在Python的Django框架中更新数据库数据的方法
2015/07/17 Python
python基于itchat实现微信群消息同步机器人
2017/02/27 Python
python实现点对点聊天程序
2018/07/28 Python
详解关于Django中ORM数据库迁移的配置
2018/10/08 Python
Django模板Templates使用方法详解
2019/07/19 Python
Django实现auth模块下的登录注册与注销功能
2019/10/10 Python
Python连接Hadoop数据中遇到的各种坑(汇总)
2020/04/14 Python
HTML5的结构和语义(4):语义性的内联元素
2008/10/17 HTML / CSS
数控技术与应用毕业生自荐信
2013/09/24 职场文书
公积金转移接收函
2014/01/11 职场文书
岳父生日宴会答谢词
2014/01/13 职场文书
企业内控岗位的职责
2014/02/07 职场文书
《桂花雨》教学反思
2014/04/12 职场文书
质量保证书范本
2014/04/29 职场文书
校园会短篇的广播稿
2014/10/21 职场文书
爱国电影观后感
2015/06/19 职场文书
春节随笔
2015/08/15 职场文书
Mysql 一主多从的部署
2022/05/20 MySQL
MySQL的表级锁,行级锁,排它锁和共享锁
2022/07/15 MySQL