https://www.jb51.net/article/87710.htm

像java一样python也可以定义一个抽象类。

在讲抽象类之前,先说下抽象方法的实现。

抽象方法是基类中定义的方法,但却没有任何实现。在java中,可以把方法申明成一个接口。而在python中实现一个抽象方法的简单的方法是:

1
2
3
class Sheep(object):
  def get_size(self):
    raise NotImplementedError

任何从Sheep继承下来的子类必须实现get_size方法。否则就会产生一个错误。但这种实现方法有个缺点。定义的子类只有调用那个方法时才会抛错。这里有个简单方法可以在类被实例化后触发它。使用python提供的abc模块。

1
2
3
4
5
6
7
import abc
class Sheep(object):
  __metaclass__ = abc.ABCMeta
   
  @abc.absractmethod
  def get_size(self):
    return

这里实例化Sheep类或任意从其继承的子类(未实现get_size)时候都会抛出异常。

因此,通过定义抽象类,可以定义子类的共同method(强制其实现)。

如何使用抽象类

1
2
3
4
5
6
7
8
9
10
11
12
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装饰器来表明抽象方法

注册具体类

1
2
3
4
5
6
7
8
9
10
11
12
13
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

从抽象类注册一个具体的类

子类化实现

1
2
3
4
5
6
7
8
9
10
11
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. 但是副作用是可以通过基类找出所有的具体类

1
2
3
4
for sc in A.__subclasses__():
  print sc.__name__
 
# print C

如果使用继承的方式会找出所有的具体类,如果使用register的方式则不会被找出

使用__subclasshook__

使用__subclasshook__后只要具体类定义了与抽象类相同的方法就认为是他的子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

不完整的实现

1
2
3
4
5
6
7
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不能实例化抽象类和抽象方法

具体类中使用抽象基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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)

打印结果

1
2
3
base class reading data
subclass sorting data
['line one', 'line two', 'line three']

可以使用super来重用抽象基类中的罗辑, 但会迫使子类提供覆盖方法.

抽象属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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.

1
2
Error: ...
print concrete property

定义抽象的读写属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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相同。如果只覆盖其中一个将不会工作.

1
2
3
4
error: ...
error: ...
print 'default value'
print 'hello'

使用装饰器语法来实现读写的抽象属性, 读和写的方法应该相同.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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中定义和使用抽象类的方法的更多相关文章

  1. 第7.22节 Python中使用super调用父类的方法

    第7.22节 Python中使用super调用父类的方法 前面章节很多地方都引入了super方法,这个方法就是访问超类这个类对象的.由于super方法的特殊性,本节单独谈一谈super方法. 一.su ...

  2. Python中的str与unicode处理方法

    Python中的str与unicode处理方法 2015/03/25 · 基础知识 · 3 评论· Python 分享到:42 原文出处: liuaiqi627 的博客    python2.x中处理 ...

  3. Python中针对函数处理的特殊方法

    Python中针对函数处理的特殊方法 很多语言都提供了对参数或变量进行处理的机制,作为灵活的Python,提供了一些针对函数处理的特殊方法 filter(function, sequence):对se ...

  4. Python中异步协程的使用方法介绍

    1. 前言 在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞.比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,程序一直在等待网站响应,最后 ...

  5. python中常用的导包的方法和常用的库

    python中常用的导包的方法               导入包和包名的方法:1.import package.module 2.from package.module import  * 例一: ...

  6. 举例详解Python中的split()函数的使用方法

    这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下   函数:sp ...

  7. Python中os和shutil模块实用方法集…

    Python中os和shutil模块实用方法集锦 类型:转载 时间:2014-05-13 这篇文章主要介绍了Python中os和shutil模块实用方法集锦,需要的朋友可以参考下 复制代码代码如下: ...

  8. Python中os和shutil模块实用方法集锦

    Python中os和shutil模块实用方法集锦 类型:转载 时间:2014-05-13 这篇文章主要介绍了Python中os和shutil模块实用方法集锦,需要的朋友可以参考下 复制代码代码如下: ...

  9. python中执行shell的两种方法总结

    这篇文章主要介绍了python中执行shell的两种方法,有两种方法可以在Python中执行SHELL程序,方法一是使用Python的commands包,方法二则是使用subprocess包,这两个包 ...

随机推荐

  1. 002.Zabbix简介

    一 Zabbix简介 1.1 概述 Zabbix是一个企业级的高度集成开源监控软件,提供分布式监控解决方案.可以用来监控设备.服务等可用性和性能. 1.2 所支持监控方式 目前由zabbix提供包括但 ...

  2. python开发之虚拟环境管理:virtualenv、virtualenvwrapper、pycharm

    1 引言 进行Python开发时,多个项目可能使用到不同的依赖,例如A项目需要1.8版本的Django,而B项目需要2.0版本的Django,这时候如果没有使用虚拟环境,就需要来回卸载和安装Djang ...

  3. puppeteer 安装失败的解决方案

    你应该也是在玩puppeteer,所以才会来到这里寻找答案,开始正文…… 安装时遇到 ERROR: Failed to download Chromium r515411! Set "PUP ...

  4. 移动端小坑:用户长按H5文字出现复制

    禁止复制方法:*{ -webkit-user-select: none;/*禁用手机浏览器的用户选择功能 */ -moz-user-select: none; -webkit-touch-callou ...

  5. ReactNative用指定的真机/模拟器运行项目

    使用模拟器运行项目: 命令行中React native项目目录下键入react-native run-ios会启动iOS模拟器, 默认是使用iPhone6,如果想要试用其他版本的模拟器则需要在reac ...

  6. JDBC连接

    jdbc是java中的数据库连接技术,功能非常强大. 数据库访问过程 1.加载数据库驱动 要通过jdbc去访问某数据库必须有相应的JDBC driver 它往往由数据库厂商提供,是链接jdbc API ...

  7. 2017.08.08【NOIP提高组】模拟赛B组

    Summary 今天的题目也不算很难,唯一一道没做出来的题目是以前做过的,太不应该了. Problem T1 油滴扩展 题目大意 给你一堆点,你准备要在这么多的点当中滴油.你可以自己安排顺序,每次滴油 ...

  8. python安装虚拟环境virtualenv

    虚拟环境 虚拟环境是一个将不同项目所需求的依赖分别放在独立的地方的一个工具,它给这些工程创建虚拟的Python环境.它解决了“项目X依赖于版本1.x,而项目Y需要项目4.x”的两难问题,而且使你的全局 ...

  9. python之面向对象的程序设计

    一.什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了程序的复杂度 缺点是: ...

  10. 问题7:JavaScript 常用正则示例

    1. trim功能(清除字符串两端空格) String.prototype.trim = function() { return this.replace(/(^\s+)|(\s+$)/g, ''); ...