在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实现微信每天给女朋友说晚安
Mar 23 Python
tensorflow 恢复指定层与不同层指定不同学习率的方法
Jul 26 Python
Python中return self的用法详解
Jul 27 Python
使用python实现语音文件的特征提取方法
Jan 09 Python
djang常用查询SQL语句的使用代码
Feb 15 Python
python利用wx实现界面按钮和按钮监听和字体改变的方法
Jul 17 Python
Python 函数绘图及函数图像微分与积分
Nov 20 Python
利用Python的turtle库绘制玫瑰教程
Nov 23 Python
Python Print实现在输出中插入变量的例子
Dec 25 Python
python 两个一样的字符串用==结果为false问题的解决
Mar 12 Python
在pycharm中使用matplotlib.pyplot 绘图时报错的解决
Jun 01 Python
python try...finally...的实现方法
Nov 25 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变量修饰符static的使用
2013/06/28 PHP
PHP给前端返回一个JSON对象的实例讲解
2018/05/31 PHP
php7 图形用户界面GUI 开发示例
2020/02/22 PHP
js escape,unescape解决中文乱码问题的方法
2010/05/26 Javascript
仅Firefox中链接A无法实现模拟点击以触发其默认行为
2011/07/31 Javascript
JavaScript异步调用定时方法并停止该方法实现代码
2012/03/16 Javascript
Javascript图像处理思路及实现代码
2012/12/25 Javascript
jQuery插件jQuery-JSONP开发ajax调用使用注意事项
2013/11/22 Javascript
jquery实现在页面加载完毕后获取图片高度或宽度
2014/06/16 Javascript
基于jQuery实现淡入淡出效果轮播图
2020/07/31 Javascript
Bootstrap 源代码分析(未完待续)
2016/08/17 Javascript
discuz表情的JS提取方法分析
2017/03/22 Javascript
JavaScript仿微信(电话)联系人列表滑动字母索引实例讲解(推荐)
2017/08/16 Javascript
详解ES6语法之可迭代协议和迭代器协议
2018/01/13 Javascript
PHPStorm中如何对nodejs项目进行单元测试详解
2019/02/28 NodeJs
javascript实现简易数码时钟
2020/03/30 Javascript
解决vue elementUI 使用el-select 时 change事件的触发问题
2020/11/17 Vue.js
可拖拽组件slider.js使用方法详解
2020/12/04 Javascript
浅谈Python单向链表的实现
2015/12/24 Python
简单谈谈Python中的几种常见的数据类型
2017/02/10 Python
Python 中pandas索引切片读取数据缺失数据处理问题
2019/10/09 Python
pytorch中tensor.expand()和tensor.expand_as()函数详解
2019/12/27 Python
pytorch 中的重要模块化接口nn.Module的使用
2020/04/02 Python
浅析Python 简单工厂模式和工厂方法模式的优缺点
2020/07/13 Python
Python 在 VSCode 中使用 IPython Kernel 的方法详解
2020/09/05 Python
python 元组和列表的区别
2020/12/30 Python
pycharm 2020.2.4 pip install Flask 报错 Error:Non-zero exit code的问题
2020/12/04 Python
CSS3新增布局之: flex详解
2020/06/18 HTML / CSS
【HTML5】3D模型--百行代码实现旋转立体魔方实例
2016/12/16 HTML / CSS
启动一个线程是用run()还是start()
2016/12/25 面试题
大学班级文化建设方案
2014/05/06 职场文书
文秘班元旦晚会活动策划方案
2014/08/28 职场文书
英语教学课后反思
2016/02/15 职场文书
2020年基层司法所建设情况调研报告
2019/11/30 职场文书
奇妙的 CSS shapes(CSS图形)
2021/04/05 HTML / CSS
Python Pygame实战在打砖块游戏的实现
2022/03/17 Python