在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多重继承新算法C3介绍
Sep 28 Python
Windows系统配置python脚本开机启动的3种方法分享
Mar 10 Python
python3序列化与反序列化用法实例
May 26 Python
python3实现TCP协议的简单服务器和客户端案例(分享)
Jun 14 Python
Python基于回溯法子集树模板解决0-1背包问题实例
Sep 02 Python
Python中pygal绘制雷达图代码分享
Dec 07 Python
Python测试网络连通性示例【基于ping】
Aug 03 Python
对python实时得到鼠标位置的示例讲解
Oct 14 Python
利用pandas合并多个excel的方法示例
Oct 10 Python
python爬虫开发之使用Python爬虫库requests多线程抓取猫眼电影TOP100实例
Mar 10 Python
python求numpy中array按列非零元素的平均值案例
Jun 08 Python
python基础之类方法和静态方法
Oct 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
PHP错误和异长常处理总结
2014/03/06 PHP
PHP图片处理之使用imagecopyresampled函数实现图片缩放例子
2014/11/19 PHP
Zend Framework教程之模型Model用法简单实例
2016/03/04 PHP
TP3.2批量上传文件或图片 同名冲突问题的解决方法
2017/08/01 PHP
php删除二维数组中的重复值方法
2018/03/12 PHP
php实现文件上传基本验证
2020/03/04 PHP
JavaScript 设计模式 富有表现力的Javascript(一)
2010/05/26 Javascript
css值转换成数值请抛弃parseInt
2011/10/24 Javascript
JavaScript Promise启示录
2014/08/12 Javascript
用Move.js配合创建CSS3动画的入门指引
2015/07/22 Javascript
json+jQuery实现的无限级树形菜单效果代码
2015/08/27 Javascript
详解javascript的变量与标识符
2016/01/04 Javascript
WordPress中利用AJAX技术进行评论提交的实现示例
2016/01/12 Javascript
使用递归遍历对象获得value值的实现方法
2016/06/14 Javascript
jQuery事件委托之Safari
2016/07/05 Javascript
Angular实现点击按钮后在上方显示输入内容的方法
2017/12/27 Javascript
element 结合vue 在表单验证时有值却提示错误的解决办法
2018/01/22 Javascript
基于Vue2.X的路由和钩子函数详解
2018/02/09 Javascript
利用Vue构造器创建Form组件的通用解决方法
2018/12/03 Javascript
微信小程序中网络请求缓存的解决方法
2019/12/29 Javascript
JavaScript如何判断对象有某属性
2020/07/03 Javascript
JS可断点续传文件上传实现代码解析
2020/07/30 Javascript
python3模拟百度登录并实现百度贴吧签到示例分享(百度贴吧自动签到)
2014/02/24 Python
python字典序问题实例
2014/09/26 Python
分享一个常用的Python模拟登陆类
2015/03/29 Python
在Django的form中使用CSS进行设计的方法
2015/07/18 Python
Python实现屏幕截图的两种方式
2018/02/05 Python
python绘制中国大陆人口热力图
2018/11/07 Python
python3图片文件批量重命名处理
2019/10/31 Python
英国Office鞋店德国网站:在线购买鞋子、靴子和运动鞋
2018/12/19 全球购物
介绍一下SQL中union,intersect和minus
2012/04/05 面试题
百度JavaScript笔试题
2015/01/15 面试题
秋季红领巾广播稿
2014/01/27 职场文书
乡镇消防工作实施方案
2014/03/27 职场文书
合伙经营协议书范本(通用版)
2014/12/03 职场文书
对PyTorch中inplace字段的全面理解
2021/05/22 Python