博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python中的对象行为与特殊方法(二)类型检查与抽象基类
阅读量:5722 次
发布时间:2019-06-18

本文共 2921 字,大约阅读时间需要 9 分钟。

类型检查

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

class Foo(object):    passf = Foo()

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

>>> type(f) == FooTrue

当然,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, abstractpropertyclass 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 AbsFileopen File

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

from abc import ABCMeta, abstractmethod, abstractpropertyclass AbsFile(object):    __metaclass__ = ABCMeta    @abstractmethod    def open(self):        pass    class File(object):    passAbsFile.register(File)

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

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

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

转载地址:http://rykwx.baihongyu.com/

你可能感兴趣的文章
Python中的对象行为与特殊方法(二)类型检查与抽象基类
查看>>
Ubuntu 16.04服务器版查看DHCP自动分配的IP、网关、DNS
查看>>
使用 axios 详解
查看>>
通信基站(dfs回溯,思维)
查看>>
nginx web加密访问
查看>>
iOS - Regex 正则表达式
查看>>
SYS_CONTEXT函数返回IP地址的一些误解
查看>>
第 68 章 Logical Volume Manager (LVM)
查看>>
膝盖中了一箭之康复篇-第八个月暨2月份目标总结
查看>>
IPA提交APPStore问题记录(一)
查看>>
有利于seo优化的网站地图不能取巧
查看>>
快照产品体验优化
查看>>
ASCII
查看>>
Spring Bean的作用域(转)
查看>>
50天!3家!共享单车终于开始了“大逃亡”
查看>>
ibatis SqlMap not found
查看>>
Android SD卡创建文件和文件夹失败
查看>>
Ubuntu 14.04 vsftp refusing to run with writable root inside chroot问题解决方法
查看>>
Intellij IDEA远程调试tomcat
查看>>
hadoop的学习论坛
查看>>