在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 (1)
Oct 31 Python
设计模式中的原型模式在Python程序中的应用示例
Mar 02 Python
python+selenium实现京东自动登录及秒杀功能
Nov 18 Python
Python中property属性实例解析
Feb 10 Python
python3.6.3安装图文教程 TensorFlow安装配置方法
Jun 24 Python
python+ffmpeg批量去视频开头的方法
Jan 09 Python
Pandas库之DataFrame使用的学习笔记
Jun 21 Python
Python 分享10个PyCharm技巧
Jul 13 Python
Python Request爬取seo.chinaz.com百度权重网站的查询结果过程解析
Aug 13 Python
Python使用正则表达式实现爬虫数据抽取
Aug 17 Python
python Pexpect模块的使用
Dec 25 Python
python中的getter与setter你了解吗
Mar 24 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
PHPMYADMIN导入数据最大为2M的解决方法
2012/04/23 PHP
php实现图片上传并利用ImageMagick生成缩略图
2016/03/14 PHP
PHP递归实现文件夹的复制、删除、查看大小操作示例
2017/08/11 PHP
按Enter键触发事件的jquery方法实现代码
2014/02/17 Javascript
jQuery中attr()和prop()在修改checked属性时的区别
2014/07/18 Javascript
node.js中的fs.readFile方法使用说明
2014/12/15 Javascript
JS实现的页面自定义滚动条效果
2015/10/26 Javascript
js实现的鼠标滚轮滚动切换页面效果(类似360默认页面滚动切换效果)
2016/01/27 Javascript
jQuery模仿单选按钮选中效果
2016/06/24 Javascript
Bootstrap select实现下拉框多选效果
2016/12/23 Javascript
jQuery中extend函数简单用法示例
2017/10/11 jQuery
JavaScript获取用户所在城市及地理位置
2018/04/21 Javascript
如何使用pm2快速将项目部署到远程服务器
2019/03/12 Javascript
vue 使用localstorage实现面包屑的操作
2020/11/16 Javascript
Python中除法使用的注意事项
2014/08/21 Python
实例讲解Python中函数的调用与定义
2016/03/14 Python
Python使用Paramiko模块编写脚本进行远程服务器操作
2016/05/05 Python
Python类的动态修改的实例方法
2017/03/24 Python
使用python脚本实现查询火车票工具
2018/07/19 Python
Python中将两个或多个list合成一个list的方法小结
2019/05/12 Python
Python OpenCV中的resize()函数的使用
2019/06/20 Python
python 实现简单的FTP程序
2019/12/27 Python
HTML5学习笔记之html5与传统html区别
2016/01/06 HTML / CSS
Swisse官方海外旗舰店:澳大利亚销量领先,自然健康品牌
2017/12/15 全球购物
英国羊绒服装购物网站:Pure Collection
2018/10/22 全球购物
农救科工作职责
2013/11/27 职场文书
社区包粽子活动方案
2014/01/21 职场文书
回门宴父母答谢词
2014/01/26 职场文书
动漫专业高职生职业生涯规划书
2014/02/15 职场文书
部队党性分析材料
2014/02/16 职场文书
购房意向书范本
2014/04/01 职场文书
纠纷协议书
2014/04/16 职场文书
《记金华的双龙洞》教学反思
2014/04/19 职场文书
建设投标担保书
2014/05/13 职场文书
民主评议党员总结
2014/10/20 职场文书
MySql学习笔记之事务隔离级别详解
2021/05/12 MySQL