在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简单日志处理类分享
Feb 14 Python
python模块之StringIO使用示例
Apr 08 Python
python中as用法实例分析
Apr 30 Python
Python统计文件中去重后uuid个数的方法
Jul 30 Python
python执行使用shell命令方法分享
Nov 08 Python
Python快速排序算法实例分析
Nov 29 Python
Python容器使用的5个技巧和2个误区总结
Sep 26 Python
Python函数的返回值、匿名函数lambda、filter函数、map函数、reduce函数用法实例分析
Dec 26 Python
Tensorflow 使用pb文件保存(恢复)模型计算图和参数实例详解
Feb 11 Python
python3发送request请求及查看返回结果实例
Apr 30 Python
python使用scapy模块实现ping扫描的过程详解
Jan 21 Python
Python写情书? 10行代码展示如何把情书写在她的照片里
Apr 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
第十五节--Zend引擎的发展
2006/11/16 PHP
php 过滤危险html代码
2009/06/29 PHP
php中使用explode查找某个字符是否存在的方法
2011/07/12 PHP
php mailer类调用远程SMTP服务器发送邮件实现方法
2016/03/04 PHP
Yii2 rbac权限控制操作步骤实例教程
2016/04/29 PHP
linux平台编译安装PHP7并安装Redis扩展与Swoole扩展实例教程
2016/09/30 PHP
Div Select挡住的解决办法
2008/08/07 Javascript
jQuery 源码分析笔记(4) Ready函数
2011/06/02 Javascript
Jquery时间验证和转换工具小例子
2013/07/01 Javascript
关于Javascript作用域链的八点总结
2013/12/06 Javascript
Javascript中的方法和匿名方法实例详解
2015/06/13 Javascript
JavaScript的jQuery库中ready方法的学习教程
2015/08/14 Javascript
Angularjs中UI Router的使用方法
2016/05/14 Javascript
微信小程序 MD5加密登录密码详解及实例代码
2017/01/12 Javascript
vue项目中的webpack-dev-sever配置方法
2017/12/14 Javascript
Vue之mixin全局的用法详解
2018/08/22 Javascript
[00:32]2018DOTA2亚洲邀请赛出场——LGD
2018/04/04 DOTA
[06:44]2018DOTA2亚洲邀请赛4.5 SOLO赛 MidOne vs Sumail
2018/04/06 DOTA
[03:35]2018年度DOTA2最佳辅助位选手5号位-完美盛典
2018/12/17 DOTA
关于你不想知道的所有Python3 unicode特性
2014/11/28 Python
pycharm安装图文教程
2017/05/02 Python
Python编程实现二分法和牛顿迭代法求平方根代码
2017/12/04 Python
tensorflow更改变量的值实例
2018/07/30 Python
对python 自定义协议的方法详解
2019/02/13 Python
用scikit-learn和pandas学习线性回归的方法
2019/06/21 Python
python用for循环求和的方法总结
2019/07/08 Python
Skyscanner新西兰:全球领先的旅游搜索网站
2019/08/26 全球购物
列车长先进事迹材料
2014/01/25 职场文书
办公室务虚会发言材料
2014/10/20 职场文书
学习普通话的体会
2014/11/07 职场文书
大学生自荐信范文
2015/03/05 职场文书
小学总务工作总结
2015/08/13 职场文书
2016年“11.11”光棍节活动总结
2016/04/05 职场文书
Django集成富文本编辑器summernote的实现步骤
2021/05/31 Python
Vertica集成Apache Hudi重磅使用指南
2022/03/31 Servers
SQL语句中EXISTS的详细用法大全
2022/06/25 MySQL