在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 相关文章推荐
Windows下使Python2.x版本的解释器与3.x共存的方法
Oct 25 Python
Python更新数据库脚本两种方法及对比介绍
Jul 27 Python
python 删除大文件中的某一行(最有效率的方法)
Aug 19 Python
Python实现动态添加属性和方法操作示例
Jul 25 Python
python print出共轭复数的方法详解
Jun 25 Python
对python特殊函数 __call__()的使用详解
Jul 02 Python
在Pytorch中计算自己模型的FLOPs方式
Dec 30 Python
Python字符串中删除特定字符的方法
Jan 15 Python
python打印文件的前几行或最后几行教程
Feb 13 Python
Python文本文件的合并操作方法代码实例
Mar 31 Python
python中实现词云图的示例
Dec 19 Python
详解pytorch创建tensor函数
Mar 22 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
一个更简单的无限级分类菜单代码
2007/01/16 PHP
phpMyAdmin自动登录和取消自动登录的配置方法
2014/05/12 PHP
PHP实现数据库统计时间戳按天分组输出数据的方法
2017/10/10 PHP
从零开始学习jQuery (二) 万能的选择器
2010/10/01 Javascript
javascript eval(func())使用示例
2013/12/05 Javascript
谷歌浏览器不支持showModalDialog模态对话框的解决方法
2014/09/22 Javascript
jQuery中height()方法用法实例
2014/12/24 Javascript
JavaScript对象属性检查、增加、删除、访问操作实例
2015/07/08 Javascript
详解JavaScript中数组的相关知识
2015/07/29 Javascript
jQuery  ready方法实现原理详解
2016/10/19 Javascript
Javascript数组中push方法用法分析
2016/10/31 Javascript
JavaScript 深层克隆对象详解及实例
2016/11/03 Javascript
jQuery插件zTree实现的基本树与节点获取操作示例
2017/03/08 Javascript
JQuery 获取Dom元素的实例讲解
2017/07/08 jQuery
React Native基础入门之调试React Native应用的一小步
2018/07/02 Javascript
vue + axios get下载文件功能
2019/09/25 Javascript
Python下使用Psyco模块优化运行速度
2015/04/05 Python
Python中的lstrip()方法使用简介
2015/05/19 Python
python3.5仿微软计算器程序
2020/03/30 Python
python dataframe常见操作方法:实现取行、列、切片、统计特征值
2018/06/09 Python
tensorflow模型文件(ckpt)转pb文件的方法(不知道输出节点名)
2020/04/22 Python
python如何调用java类
2020/07/05 Python
使用PyCharm安装pytest及requests的问题
2020/07/31 Python
HTML5 HTMLCollection和NodeList的区别详解
2020/04/29 HTML / CSS
资产评估专业大学生求职信
2013/09/29 职场文书
2013年军训通讯稿
2014/02/05 职场文书
父亲的菜园教学反思
2014/02/13 职场文书
六查六看剖析材料
2014/02/15 职场文书
建筑结构施工专业推荐信
2014/02/21 职场文书
超市中秋节促销方案
2014/03/21 职场文书
五一促销活动总结
2014/07/01 职场文书
效能风暴心得体会
2014/09/04 职场文书
表扬信格式模板
2015/05/05 职场文书
家庭经济困难证明
2015/06/23 职场文书
如何用python识别滑块验证码中的缺口
2021/04/01 Python
spring cloud 配置中心native配置方式
2021/09/25 Java/Android