类型检查

创建类的实例时,该实例的类型为类本身:

class Foo(object):
pass f = Foo()

要测试实例是否属于某个类,可以使用type()内置函数:

>>> type(f) == Foo
True

当然,python中不建议如此检查,更好的办法是使用内置类型检查函数isinstance(obj, cls):

>>> isinstance(f, Foo)
True

同样的,内置函数issubclass(cls1, cls2)可以用做子类的检查:

class SubFoo(Foo):
pass >>> issubclass(SubFoo, Foo)
True

这两个内置函数的第二个参数可以是一个单独的类,也可以是几个类的元组:

>>> isinstance(1, (str, int))
True

以下两个特殊方法可用于重新定义这两个内置函数:

__instancecheck__(cls, obj)

__subclasscheck__(cls, subcls)

鸭子类型

python是门动态语言,调用对象的时候是不用考虑对象的类型的,而只需要对象有某些特定的属性或者行为即可,也就是鸭子类型。

为了保持程序的松散耦合,我们可以不用继承,而只是模仿一些对象的行为:

class File(object):
def open(self):
print 'open File' class FileLike(object):
def open(self):
print 'open FileLike' def foo(f):
f.open()

只要定义了open()方法的实例,就可以作为函数foo()的参数:

>>> f = File()
>>> fl = FileLike()
>>> foo(f)
open File
>>> foo(fl)
open FileLike

当我们测试对象是否可以作为foo()的参数时,要同时进行两次isinstance()类型检查,如果类型更多的话呢?

现在我们可以将File和FileLike分组并对其进行一次类型检查:

class FileLikeClass(object):
def __init__(self):
self.reg = set() def register(self, cls):
self.reg.add(cls) def __instancecheck__(self, obj):
return self.__subclasscheck__(type(obj)) def __subclasscheck__(self, subcls):
return any(cls in self.reg for cls in subcls.mro()) flc = FileLikeClass()
flc.register(File)
flc.register(FileLike)

上述代码使用FileLikeClass创造一个对象,将要检查的类型放入对象的一个集合属性中,然后重新定义__instancecheck__(cls, obj)与__subclasscheck__(cls, subcls)方法,

进行子类检查时,会检查子类及子类的基类是否在集合中,进行类型检查时,会检查对象的类型是否是集合中的类的子类:

>>> f = File()
>>> isinstance(f, flc)
True
>>> fl = FileLike()
>>> isinstance(fl, flc)
True

当然,python提供了一种更正式的机制来分组对象,定义接口并进行类型检查----抽象基类

抽象基类

要定义抽象基类,需要使用abc模块,该模块定义一个元类(ABCMeta)和两个装饰器(@abstractmethod,抽象方法)与(@abstractproperty, 抽象特性),使用方法如下:

from abc import ABCMeta, abstractmethod, abstractproperty

class AbsFile(object):
__metaclass__ = ABCMeta @abstractmethod
def open(self):
pass

抽象基类就是定义各种方法而不做具体实现的类,抽象基类是无法实例化的:

>>> AbsFile()
TypeError: Can't instantiate abstract class AbsFile with abstract methods open

任何继承自抽象基类的类也必须实现这些方法,否则无法实例化:

class File(AbsFile):
pass

实例化失败:

>>> File()
TypeError: Can't instantiate abstract class File with abstract methods open

需定义open方法:

class File(AbsFile):
def open(self):
print 'open File'

当然抽象基类中也可以对抽象方法进行具体实现,在子类中可以通过super()来调用:

class AbsFile(object):
__metaclass__ = ABCMeta @abstractmethod
def open(self):
print 'open AbsFile' class File(AbsFile):
def open(self):
super(File, self).open()
print 'open File'

实例化:

>>> File().open()
open AbsFile
open File

如果只想执行类型检查的话,可以使用register()方法:

from abc import ABCMeta, abstractmethod, abstractproperty

class AbsFile(object):
__metaclass__ = ABCMeta @abstractmethod
def open(self):
pass class File(object):
pass AbsFile.register(File)

向抽象基类注册某个类时,是不会检查该类是否实现了抽象基类的抽象方法或者特性的,只会影响类型检查:

>>> f = File()
>>> isinstance(f, AbsFile)
True

python的collections模块定义了与序列,集合和字典有关的各种抽象基类,numbers模块定义了与数字有关的抽象基类。

Python中的对象行为与特殊方法(二)类型检查与抽象基类的更多相关文章

  1. Python中的对象行为与特殊方法(一)对象的创建与销毁

    Python中类调用__new__()类方法来创建实例,调用__init__()方法来初始化对象,对象的销毁则调用__del__()方法. __new__()方法第一个参数为类cls,通常返回cls的 ...

  2. python中json对象转换出错解决方法

    今天在使用python中的json转换碰到一个问题: 接收一个post的json字符串: s={"username":"admin","passwor ...

  3. python中的json的基本使用方法

    在python中使用json的时候,主要也就是使用json模块,json是以一种良好的格式来进行数据的交互,从而在很多时候,可以使用json数据格式作为程序之间的接口, #!/usr/bin/env ...

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

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

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

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

  6. python之抽象基类

    抽象基类特点 1.不能够实例化 2.在这个基础的类中设定一些抽象的方法,所有继承这个抽象基类的类必须覆盖这个抽象基类里面的方法 思考 既然python中有鸭子类型,为什么还要使用抽象基类? 一是我们在 ...

  7. Python抽象基类之声明协议

    抽象基类之--声明协议 上回讲了Python中抽象基类的大概,相信大家对abcmeta以及什么是抽象基类已经有所了解.传送门 现在我们来讲讲抽象基类的另一个常用用法--声明协议 所谓声明协议,有点像J ...

  8. Python抽象基类:ABC谢谢你,因为有你,温暖了四季!

    Python抽象基类:ABC谢谢你,因为有你,温暖了四季! Python抽象基类:ABC谢谢你,因为有你,温暖了四季! 实例方法.类方法和静态方法 抽象类 具名元组 参考资料 最近阅读了<Pyt ...

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

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

随机推荐

  1. Mysql自增ID起始值修改

    在mysql中很多朋友都认为字段为AUTO_INCREMENT类型自增ID值是无法修改,其实这样理解是错误的,下面介绍mysql自增ID的起始值修改与设置方法.通常的设置自增字段的方法:创建表格时添加 ...

  2. Ubuntu系统添加搜狗输入法

    前端开发时有时候要接触到Ubuntu系统,但由于本身没有拼音输入,故需要自己安装搜狗,记录方法如下: 1.安装前先升级资源库并安装输入法依赖包: $sudo apt-get update $sudo ...

  3. c#之课后习题

    1.折叠代码 #region 折叠内容#endregion 2.保留三位小数 using System; namespace _005_double保留3位小数 { class Program { s ...

  4. div上下左右居中方法

    方法一:在浏览器中只有一个div的情况 { position:fixed; position:fixed; ; ; ; ; margin:auto; } 方法一 方法二:一个父元素div和一个已知宽度 ...

  5. HTML5特效收录-不定时更新

    在工作中,我们可能会用到各种交互效果.而这些效果在平常翻看文章的时候碰到很多,但是一时半会又想不起来在哪,所以养成知识整理的习惯是很有必要的.希望能给大大家启发,并且学习. HTML5 Canvas粒 ...

  6. 在caffe-ssd安装编译环境运行make all时候报错:Makefile:572: recipe for target '.build_release/src/caffe/util/hdf5.o' failed make: *** [.build_release/src/caffe/util/hdf5.o] Error 1

    解决办法: 修改:Makefile.config INCLUDE_DIRS /usr/include/hdf5/serial/ 修改:Makefile LIBRARIES hdf5_hl and hd ...

  7. C#基础知识整理

    年时,北风吹雁雪纷纷,一条秋裤冻上头.冷的连手都懒得动,就随便翻翻书,也没有更新博客,如今年已过,开始投入到正常的工作状态中,趁现在需求还没有来,把C#基础知识梳理一下,其实一直以来就想这样做的,对于 ...

  8. Spark学习之路 (二)Spark2.3 HA集群的分布式安装

    一.下载Spark安装包 1.从官网下载 http://spark.apache.org/downloads.html 2.从微软的镜像站下载 http://mirrors.hust.edu.cn/a ...

  9. urllib2 post请求方式,带cookie,添加请求头

    #encoding = utf-8 import urllib2import urllib url = 'http://httpbin.org/post'data={"name": ...

  10. Linux基础命令---文本格式转换fmt

    fmt 将指定文件的内容,按照指定的格式重新排版,结果送到标准输出. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.openSUSE.Fedora. 1.语法     ...