上一篇介绍了Python中类相关的一些基本点,本文看看Python中类的继承和__slots__属性。

继承

在Python中,同时支持单继承与多继承,一般语法如下:

classSubClassName(ParentClass1 [, ParentClass2, ...]):

class_suite

实现继承之后,子类将继承父类的属性,也可以使用内建函数insubclass()来判断一个类是不是另一个类的子孙类:

classParent(object):'''parent class'''numList=[]defnumAdd(self, a, b):return a+bclassChild(Parent):passc=Child()#subclass will inherit attributes from parent class

Child.numList.extend(range(10))printChild.numListprint "2 + 5 =", c.numAdd(2, 5)#built-in function issubclass()

printissubclass(Child, Parent)printissubclass(Child, object)#__bases__ can show all the parent classes

print Child.__bases__

#doc string will not be inherited

print Parent.__doc__

print Child.__doc__

代码的输出为,例子中唯一特别的地方是文档字符串。文档字符串对于类,函数/方法,以及模块来说是唯一的,也就是说__doc__属性是不能从父类中继承来的。

继承中的__init__

当在Python中出现继承的情况时,一定要注意初始化函数__init__的行为。

1. 如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用;但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错。

classParent(object):def __init__(self, data):

self.data=dataprint "create an instance of:", self.__class__.__name__

print "data attribute is:", self.dataclassChild(Parent):passc= Child("init Child")printc= Child()

代码的输出为:

2. 如果子类定义了自己的初始化函数,而没有显示调用父类的初始化函数,则父类的属性不会被初始化

classParent(object):def __init__(self, data):

self.data=dataprint "create an instance of:", self.__class__.__name__

print "data attribute is:", self.dataclassChild(Parent):def __init__(self):print "call __init__ from Child class"c=Child()print c.data

代码的输出为:

3. 如果子类定义了自己的初始化函数,显示调用父类,子类和父类的属性都会被初始化

classParent(object):def __init__(self, data):

self.data=dataprint "create an instance of:", self.__class__.__name__

print "data attribute is:", self.dataclassChild(Parent):def __init__(self):print "call __init__ from Child class"super(Child, self).__init__("data from Child")

c=Child()print c.data

代码的输出为:

super

前面一个例子中,已经看到了通过super来调用父类__init__方法的例子,下面看看super的使用。

在子类中,一般会定义与父类相同的属性(数据属性,方法),从而来实现子类特有的行为。也就是说,子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的属性和方法。

classParent(object):

fooValue= "Hi, Parent foo value"

deffoo(self):print "This is foo from Parent"

classChild(Parent):

fooValue= "Hi, Child foo value"

deffoo(self):print "This is foo from Child"c=Child()

c.foo()print Child.fooValue

在这段代码中,子类的属性"fooValue"和"foo"覆盖了父类的属性,所以子类有了自己的行为。

但是,有时候可能需要在子类中访问父类的一些属性:

classParent(object):

fooValue= "Hi, Parent foo value"

deffoo(self):print "This is foo from Parent"

classChild(Parent):

fooValue= "Hi, Child foo value"

deffoo(self):print "This is foo from Child"

printParent.fooValue#use Parent class name and self as an argument

Parent.foo(self)

c=Child()

c.foo()

这时候,可以通过父类名直接访问父类的属性,当调用父类的方法是,需要将"self"显示的传递进去的方式。

这种方式有一个不好的地方就是,需要经父类名硬编码到子类中,为了解决这个问题,可以使用Python中的super关键字:

classParent(object):

fooValue= "Hi, Parent foo value"

deffoo(self):print "This is foo from Parent"

classChild(Parent):

fooValue= "Hi, Child foo value"

deffoo(self):print "This is foo from Child"

#use super to access Parent attribute

printsuper(Child, self).fooValue

super(Child, self).foo()

c=Child()

c.foo()

对于"super(Child, self).foo()"可以理解为,首先找到Child的父类Parent,然后调用父类的foo方法,同时将Child的实例self传递给foo方法。

但是,如果当一个子类有多个父类的时候,super会如何工作呢?这是就需要看看MRO的概念了。

MRO

假设现在有一个如下的继承结构,首先通过类名显示调用的方式来调用父类的初始化函数:

classA(object):def __init__(self):print "->Enter A"

print "<-Leave A"

classB(A):def __init__(self):print "-->Enter B"A.__init__(self)print "<--Leave B"

classC(A):def __init__(self):print "--->Enter C"A.__init__(self)print "<---Leave C"

classD(B, C):def __init__(self):print "---->Enter D"B.__init__(self)

C.__init__(self)print "<----Leave D"d= D()

从输出中可以看到,类A的初始化函数被调用了两次,这不是我们想要的结果:

下面,我们通过super方式来调用父类的初始化函数:

classA(object):def __init__(self):print "->Enter A"

print "<-Leave A"

classB(A):def __init__(self):print "-->Enter B"super(B, self).__init__()print "<--Leave B"

classC(A):def __init__(self):print "--->Enter C"super(C, self).__init__()print "<---Leave C"

classD(B, C):def __init__(self):print "---->Enter D"super(D, self).__init__()print "<----Leave D"d= D()

通过输出可以看到,当使用super后,A的初始化函数只能调用了一次:

为什么super会有这种效果?下面就开始看看Python中的方法解析顺序MRO(Method Resolution Order)。

Python的类有一个__mro__属性,这个属性中就保存着方法解析顺序。结合上面的例子来看看类D的__mro__:

>>> print "MRO:", [x.__name__ for x in D.__mro__]

MRO: ['D', 'B', 'C', 'A', 'object']>>>

看到这里,对于上面使用super例子的输出就应该比较清楚了。

Python的多继承类是通过MRO的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数只调用一次(如果每个类都使用super)

混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一个父类函数被调用多次

__slots__

从前面的介绍可以看到,当我们通过一个类创建了实例之后,仍然可以给实例添加属性,但是这些属性只属于这个实例。

有些时候,我们可以需要限制类实例对象的属性,这时就要用到类中的__slots__属性了。__slots__属性对于一个tuple,只有这个tuple中出现的属性可以被类实例使用。

classStudent(object):__slots__ = ("name", "age")def __init__(self, name, age):

self.name=name

self.age=age

s= Student("Wilber", 28)print "%s is %d years old" %(s.name, s.age)

s.score= 96

在这个例子中,当场是给Student的实例s添加一个score属性的时候,就会遇到下面的异常:

子类没有__slots__属性

使用__slots__要注意,__slots__定义的属性仅对当前类的实例起作用,对继承的子类实例是不起作用的:

classPerson(object):__slots__ = ("name", "age")pass

classStudent(Person):passs=Student()

s.name, s.age= "Wilber", 28s.score= 100

print "%s is %d years old, score is %d" %(s.name, s.age, s.score)

从代码的输出可以看到,子类Student的实例并不受父类中__slots__属性的限制:

子类拥有__slots__属性

但是,如果子类本身也有__slots__属性,子类的属性就是自身的__slots__加上父类的__slots__。

classPerson(object):__slots__ = ("name", "age")pass

classStudent(Person):__slots__ = ("score", )passs=Student()

s.name, s.age= "Wilber", 28s.score= 100

print "%s is %d years old, score is %d" %(s.name, s.age, s.score)print s.__slots__s.city= "Shanghai"

代码的输出为:

所以说,对于__slots__属性:

如果父类包含对__slots__的定义,子类不包含对__slots__的定义,解释器忽略__slots__的作用

如果父类包含对__slots__的定义,子类包含对__slots__的定义,并且无论元组的的元素个数,解释器都会按照父类的__slots__和子类的__slots__的并集来检查

总结

本文介绍了Python中的继承,当使用多继承的时候,可以使用super关键字去访问父类中被子类覆盖的方法;对于方法的调用,需要参照MRO。

另外介绍了Python类的__slots__属性,通过这个属性可以限制类实例的可用属性。

python的类中包含什么_Python中的类(中)相关推荐

  1. python中的类属性和类方法_Python 面向对象,类的属性和 类的方法

    面向对象,类的属性和 类的方法 面向对象 类和对象 Python类定义 类属性 类方法 面向过程和面向对象 面向过程 和 面向对象 编程 面向过程 编程:函数式编程,C程序,shell等 面向对象 编 ...

  2. python docx 合并文档 图片_Python检查Word文件中包含特定关键字的所有页码

    推荐教材:<Python程序设计基础与应用>(ISBN:9787111606178),董付国,机械工业出版社图书详情:配套资源:用书教师可以联系董老师获取教学大纲.课件.源码.教案.考试系 ...

  3. python类中数据成员_Python 入门 之 类成员

    1.类的私有成员 私有: 只能自己拥有 以 __ 开头就是私有内容 对于每一个类的成员而言都有两种形式: - 公有成员,在任何地方都能访问 - 私有成员,只有在类的内部才能使用 私有成员和公有成员的访 ...

  4. python中frame用法_Python实例之wxpython中Frame使用方法

    本节为大家分享的例子是wxpython Frame的用法. 例子: 代码如下: #!/usr/bin/python # -*- coding: GBK -*- # simple.py import w ...

  5. python怎么从excel获取数据_python怎么从excel中读取数据?/python 读取 excle

    如何通过python快速输出数据库数据到excel 扩展库 xlrd 读excle xlwt 写excle 直接度就能下载 下载后使用 import xlrd 就可excle文件了 打开文件: xls ...

  6. python字符串提取数字并求和_python实现将字符串中的数字提取出来然后求和

    因工作原因,很久没有学习python知识了,感觉都快忘记了,前天看到一个练习题,如何将字符串中的数字提取出来,然后求和呢?下面我来解释一下如何通过python代码来实现. 题目:字符串43...3y2 ...

  7. python将输入值转化为元组_Python实现将元组中的元素作为参数传入函数的操作

    本文由Markdown语法编辑器编辑完成. 1. 需求: 现在有一个Python的需求需要实现: 就是实现连接一次数据库,就能够执行多条SQL语句,而且这个SQL语句是需要通过调用者将每一次执行的参数 ...

  8. python文件移动到文件夹_python – 将文件夹中的文件移动到顶级目录

    我正在尝试为我的工作完成一个清理文件组织系统的脚本.我的脚本的最后一部分需要进入给定目录中的所有文件夹,并将每个文件夹中的所有文件移动到目录中.例如: import os path = 'C:/Use ...

  9. python web 框架的flash消息_python web开发-flask中消息闪现flash的应用

    Flash中的消息闪现,在官方的解释是用来给用户做出反馈.不过实际上这个功能只是一个记录消息的方法,在某一个请求中记录消息,在下一个请求中获取消息,然后做相应的处理,也就是说flask只存在于两个相邻 ...

最新文章

  1. 动软代码生成V2.74模版简介
  2. 20145217信息安全系统设计基础第11周学习总结
  3. IAR 中打多个断点出现 one or more breakpoints coule not be set and have been disabled原因及解决方案
  4. 一起谈.NET技术,ASP.NET MVC2实现分页和右键菜单
  5. 想成为嵌入式程序员应知道的0x10个基本问题
  6. android sqlite查询某个字段,Android的sqlite:如何检索特定列的特定数据?
  7. 中国地质大学计算机地理信息学院,英文主页 软件工程、计算机科学与技术、地理信息科学等相关专业学生 中国地质大学(武汉)教师个人主页系统...
  8. DevExpress ActiveX
  9. java高质量图片压缩
  10. .NET与SAP的来往(转)
  11. 11. JavaScript 对象
  12. 树莓派安装MPlayer播放器
  13. 未能对git remote进行身份验证
  14. Tomcat在IIS下同端口运行方法(我用的tomcat8.5 iis 10网上各种坑)
  15. java动态代理(AOP)
  16. 基于微信小程序的疫情智慧社区管理系统 计算机毕业设计 后台管理系统
  17. 移动端(手机端)页面自适应解决方案—rem布局篇 1
  18. Python数据分析和挖掘之入门理论+实操
  19. c语言程序实践感受心得,C语言实践心得体会
  20. st7920驱动OCMJ2X8C屏使用CGRAM自定义图标

热门文章

  1. 分享一次生产应用无法连接Oracle数据库故障
  2. Redis 安装部署介绍
  3. MySQL之 XtraBackup 备份
  4. java学习,不定期更新~
  5. java中的原型模式_java中的原型模式理解
  6. Spring/Spring boot正确集成Quartz及解决@Autowired失效问题
  7. Python安装xlrd和xlwt的步骤以及使用报错的解决方法
  8. 如何在C / Objective-C中跨多行拆分字符串文字?
  9. 静态类型和动态类型的语言有什么区别?
  10. 在Python中给定包含该项目的列表的情况下查找项目的索引