在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获取网页状态码示例
Mar 30 Python
Python中使用装饰器来优化尾递归的示例
Jun 18 Python
django中模板的html自动转意方法
May 27 Python
python调用百度地图WEB服务API获取地点对应坐标值
Jan 16 Python
Django Channels 实现点对点实时聊天和消息推送功能
Jul 17 Python
Python IDE Pycharm中的快捷键列表用法
Aug 08 Python
python中用logging实现日志滚动和过期日志删除功能
Aug 20 Python
PyTorch在Windows环境搭建的方法步骤
May 12 Python
Python函数必须先定义,后调用说明(函数调用函数例外)
Jun 02 Python
openCV提取图像中的矩形区域
Jul 21 Python
python中的插入排序的简单用法
Jan 19 Python
python字典的元素访问实例详解
Jul 21 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
浅谈Windows下 PHP4.0与oracle 8的连接设置
2006/10/09 PHP
php分页函数示例代码分享
2014/02/24 PHP
thinkphp数据查询和遍历数组实例
2014/11/28 PHP
php去除头尾空格的2种方法
2015/03/16 PHP
phpcms实现验证码替换及phpcms实现全站搜索功能教程详解
2017/12/13 PHP
关于onScroll事件在IE6下每次滚动触发三次bug说明
2011/09/21 Javascript
六款帮助你实现惊艳视差滚动效果的jQuery插件
2012/09/14 Javascript
js判断IE浏览器版本过低示例代码
2013/11/22 Javascript
一个html5播放视频的video控件只支持android的默认格式mp4和3gp
2014/05/08 Javascript
14款NodeJS Web框架推荐
2014/07/11 NodeJs
常用的jQuery前端技巧收集
2014/12/24 Javascript
JS基于VML技术实现的五角星礼花效果代码
2015/10/26 Javascript
Angular.js回顾ng-app和ng-model使用技巧
2016/04/26 Javascript
灵活使用数组制作图片切换js实现
2016/07/28 Javascript
Bootstrap基本插件学习笔记之标签切换(17)
2016/12/08 Javascript
jquery 手势密码插件
2017/03/17 Javascript
JS+CSS实现下拉刷新/上拉加载插件
2017/03/31 Javascript
JavaScript常见事件对象与操作实例总结
2019/01/05 Javascript
Vuex中的State使用介绍
2019/01/19 Javascript
JavaScript Canvas编写炫彩的网页时钟
2019/10/16 Javascript
在vue+element ui框架里实现lodash的debounce防抖
2019/11/13 Javascript
pandas数据分组和聚合操作方法
2018/04/11 Python
django 将model转换为字典的方法示例
2018/10/16 Python
Python根据文件名批量转移图片的方法
2018/10/21 Python
python 正则表达式贪婪模式与非贪婪模式原理、用法实例分析
2019/10/14 Python
flask框架json数据的拿取和返回操作示例
2019/11/28 Python
Python实现动态循环输出文字功能
2020/05/07 Python
CSS3旋转——彩色扇子兼容firefox浏览器
2013/06/04 HTML / CSS
CSS3模拟IOS滑动开关效果
2016/09/28 HTML / CSS
运动会解说词100字
2014/01/31 职场文书
法制宣传标语
2014/06/23 职场文书
自我评价优缺点范文
2015/03/11 职场文书
演讲开场白台词大全
2015/05/29 职场文书
瞿秋白纪念馆观后感
2015/06/10 职场文书
入党转正申请书范文
2019/05/20 职场文书
Python内置类型集合set和frozenset的使用详解
2022/04/26 Python