在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 相关文章推荐
rhythmbox中文名乱码问题解决方法
Sep 06 Python
简述Python中的进程、线程、协程
Mar 18 Python
python中import reload __import__的区别详解
Oct 16 Python
Python基础之文件读取的讲解
Feb 16 Python
PYQT5设置textEdit自动滚屏的方法
Jun 14 Python
Django Docker容器化部署之Django-Docker本地部署
Oct 09 Python
python集合常见运算案例解析
Oct 17 Python
python代码如何实现余弦相似性计算
Feb 09 Python
解决pycharm不能自动补全第三方库的函数和属性问题
Mar 12 Python
TensorFlow的reshape操作 tf.reshape的实现
Apr 19 Python
python 用struct模块解决黏包问题
Nov 07 Python
用python对oracle进行简单性能测试
Dec 05 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日期处理函数 整型日期格式
2011/01/12 PHP
PHP curl 并发最佳实践代码分享
2012/09/05 PHP
php实现多城市切换特效
2015/08/09 PHP
又拍云异步上传实例教程详解
2016/04/19 PHP
php获取远程图片并下载保存到本地的方法分析
2016/10/08 PHP
php中引用&amp;的用法分析【变量引用,函数引用,对象引用】
2016/12/12 PHP
PHP实现微信公众号验证Token的示例代码
2019/12/16 PHP
PHP中用Trait封装单例模式的实现
2019/12/18 PHP
客户端脚本中常常出现的一些问题和调试技巧
2007/01/09 Javascript
javascript 获取表单file全路径
2009/12/31 Javascript
js计算精度问题小结
2013/04/22 Javascript
JavaScript中使用Math.floor()方法对数字取整
2015/06/15 Javascript
jQuery实现本地预览上传图片功能
2016/01/08 Javascript
js小数计算小数点后显示多位小数的实现方法
2016/05/30 Javascript
JavaScript提高加载和执行效率的方法
2017/02/03 Javascript
ES6中Array.includes()函数的用法
2017/09/20 Javascript
Grunt针对静态文件的压缩,版本控制打包的实例讲解
2017/09/29 Javascript
Angular resolve基础用法详解
2018/10/03 Javascript
python每次处理固定个数的字符的方法总结
2013/01/29 Python
Python的另外几种语言实现
2015/01/29 Python
查看Django和flask版本的方法
2018/05/14 Python
详解centos7+django+python3+mysql+阿里云部署项目全流程
2019/11/15 Python
关于numpy中eye和identity的区别详解
2019/11/29 Python
tensorflow安装成功import tensorflow 出现问题
2020/04/16 Python
Python中过滤字符串列表的方法
2020/12/22 Python
英国航空官网:British Airways
2016/09/11 全球购物
兰蔻法国官方网站:Lancôme法国
2020/02/22 全球购物
校园门卫岗位职责
2013/12/09 职场文书
《难忘的泼水节》教学反思
2014/02/27 职场文书
总经理人事任命书
2014/06/05 职场文书
小学运动会宣传稿
2015/07/23 职场文书
导游词之杭州西湖
2019/09/19 职场文书
百善孝为先:关于孝道的经典语录
2019/10/18 职场文书
导游词之西安骊山
2019/12/20 职场文书
Java各种比较对象的方式的对比总结
2021/06/20 Java/Android
【D4DJ】美少女DJ企划 动画将于明年冬季开播第2季
2022/04/11 日漫