在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创建列表并给列表赋初始值的方法
Jul 28 Python
利用Python爬取微博数据生成词云图片实例代码
Aug 31 Python
python数字图像处理实现直方图与均衡化
May 04 Python
Django使用AJAX调用自己写的API接口的方法
Mar 06 Python
django搭建项目配置环境和创建表过程详解
Jul 22 Python
PyQt5基本控件使用详解:单选按钮、复选框、下拉框
Aug 05 Python
python 魔法函数实例及解析
Sep 25 Python
如何基于python操作excel并获取内容
Dec 24 Python
带你彻底搞懂python操作mysql数据库(cursor游标讲解)
Jan 06 Python
python实现文件分片上传的接口自动化
Nov 19 Python
Python爬虫爬取全球疫情数据并存储到mysql数据库的步骤
Mar 29 Python
python中subplot大小的设置步骤
Jun 28 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插入排序实现代码
2013/04/04 PHP
php正则取img标记中任意属性(正则替换去掉或改变图片img标记中的任意属性)
2013/08/13 PHP
PHP整数取余返回负数的相关解决方法
2014/05/15 PHP
php实现session自定义会话处理器的方法
2015/01/27 PHP
PHP编译安装时常见错误解决办法
2015/05/28 PHP
Yii2框架实现注册和登录教程
2016/09/30 PHP
Prototype Class对象学习
2009/07/19 Javascript
jquery 弹出层实现代码
2009/10/30 Javascript
javascript克隆对象深度介绍
2012/11/20 Javascript
Firefox下无法正常显示年份的解决方法
2014/09/04 Javascript
node.js下when.js 的异步编程实践
2014/12/03 Javascript
vue实现简单实时汇率计算功能
2017/01/15 Javascript
node 命令方式启动修改端口的方法
2018/05/12 Javascript
Linux Centos7.2下安装nodejs&amp;npm配置全局路径的教程
2018/05/15 NodeJs
使用JavaScript中的lodash编写双色球效果
2018/06/24 Javascript
ant-design-vue 实现表格内部字段验证功能
2019/12/16 Javascript
Javascript节流函数throttle和防抖函数debounce
2020/12/03 Javascript
快速入门python学习笔记
2017/12/06 Python
Python3.x爬虫下载网页图片的实例讲解
2018/05/22 Python
pandas 实现字典转换成DataFrame的方法
2018/07/04 Python
Python模块相关知识点小结
2020/03/09 Python
Python爬虫爬取电影票房数据及图表展示操作示例
2020/03/27 Python
PyCharm+Pipenv虚拟环境开发和依赖管理的教程详解
2020/04/16 Python
如何向scrapy中的spider传递参数的几种方法
2020/11/18 Python
详解CSS3 filter:drop-shadow滤镜与box-shadow区别与应用
2020/08/24 HTML / CSS
详解利用css3的var()实现运行时改变scss的变量值
2021/03/02 HTML / CSS
Avène雅漾美国官方网站:敏感肌肤护理专家
2016/10/24 全球购物
英国奢侈品在线精品店:Hervia
2020/09/03 全球购物
好军嫂事迹材料
2014/01/15 职场文书
数控技校生自我鉴定
2014/04/19 职场文书
论文诚信承诺书
2014/05/23 职场文书
询价采购方案
2014/06/09 职场文书
教师党的群众路线教育实践活动学习笔记
2014/11/05 职场文书
幼师大班个人总结
2015/02/13 职场文书
2015年行政人事部工作总结
2015/05/13 职场文书
游戏开发中如何使用CocosCreator进行音效处理
2021/04/14 Javascript