在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通过pil模块将raw图片转换成png图片的方法
Mar 16 Python
Python实现删除文件但保留指定文件
Jun 21 Python
python文件与目录操作实例详解
Feb 22 Python
Windows安装Python、pip、easy_install的方法
Mar 05 Python
matplotlib设置legend图例代码示例
Dec 19 Python
pandas创建新Dataframe并添加多行的实例
Apr 08 Python
Python实现图片转字符画的代码实例
Feb 22 Python
Django应用程序入口WSGIHandler源码解析
Aug 05 Python
python框架flask表单实现详解
Nov 04 Python
pycharm安装及如何导入numpy
Apr 03 Python
经验丰富程序员才知道的8种高级Python技巧
Jul 27 Python
详解Python模块化编程与装饰器
Jan 16 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/07/23 PHP
php使用fsockopen函数发送post,get请求获取网页内容的方法
2014/11/15 PHP
PHP中功能强大却很少使用的函数实例小结
2016/11/10 PHP
浅析js设置控件的readonly与enabled属性问题
2013/12/25 Javascript
javascript实现设置、获取和删除Cookie的方法
2015/06/01 Javascript
javascript父子页面通讯实例详解
2015/07/17 Javascript
JS实现IE状态栏文字缩放效果代码
2015/10/24 Javascript
bootstrap实现弹窗和拖动效果
2016/01/03 Javascript
vue分页组件table-pagebar使用实例解析
2020/11/15 Javascript
jQuery tagsinput在h5邮件客户端中应用详解
2016/09/26 Javascript
用vue构建多页面应用的示例代码
2017/09/20 Javascript
基于jquery.page.js实现分页效果
2018/01/01 jQuery
ionic2中使用自动生成器的方法
2018/03/04 Javascript
[59:44]2018DOTA2亚洲邀请赛 3.31 小组赛 B组 paiN vs iG
2018/03/31 DOTA
Python实现在matplotlib中两个坐标轴之间画一条直线光标的方法
2015/05/20 Python
详解Python装饰器由浅入深
2016/12/09 Python
python使用opencv读取图片的实例
2017/08/17 Python
浅谈关于Python3中venv虚拟环境
2018/08/01 Python
python3爬虫怎样构建请求header
2018/12/23 Python
Python Django 添加首页尾页上一页下一页代码实例
2019/08/21 Python
wxpython多线程防假死与线程间传递消息实例详解
2019/12/13 Python
python3 字符串知识点学习笔记
2020/02/08 Python
python GUI库图形界面开发之PyQt5不规则窗口实现与显示GIF动画的详细方法与实例
2020/03/09 Python
使用html5 canvas绘制圆环动效
2019/06/03 HTML / CSS
HTML5超文本标记语言的实现方法
2020/09/24 HTML / CSS
TripAdvisor印尼站:全球领先的旅游网站
2018/03/15 全球购物
匈牙利墨盒和碳粉购买网站:CDRmarket
2018/04/14 全球购物
广州迈达威.net面试题目
2012/03/10 面试题
毕业生自荐信的主要内容
2013/10/29 职场文书
就业协议书的作用
2014/04/11 职场文书
离婚协议书的范本
2015/01/27 职场文书
幼儿园毕业致辞
2015/07/29 职场文书
中学语文教学反思
2016/02/16 职场文书
python 实现德洛内三角剖分的操作
2021/04/22 Python
详解nginx location指令
2022/01/18 Servers
千万级用户系统SQL调优实战分享
2022/03/03 MySQL