Python学习总结19:类(二)
参考:http://python.jobbole.com/82308/
继承和__slots__属性
1. 继承
在Python中,同时支持单继承与多继承,一般语法如下:
class SubClassName(ParentClass1 [, ParentClass2, ...]):
class_suite
实现继承之后,子类将继承父类的属性,也可以使用内建函数insubclass()来判断一个类是不是另一个类的子孙类:
class Parent(object):
''' parent class '''
numList = []
def numAdd(self, a, b):
return a+b
class Child(Parent):
pass c = Child()
# subclass will inherit attributes from parent class
Child.numList.extend(range(10))
print Child.numList
print "2 + 5 =", c.numAdd(2, 5) # built-in function issubclass()
print issubclass(Child, Parent)
print issubclass(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__属性是不能从父类中继承来的。
1)继承中的__init__
当在Python中出现继承的情况时,一定要注意初始化函数__init__的行为。
如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用;但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错。
class Parent(object):
def __init__(self, data):
self.data = data
print "create an instance of:", self.__class__.__name__
print "data attribute is:", self.data class Child(Parent):
pass c = Child("init Child")
d = Child()
d 实例化的时候出错。
如果子类定义了自己的初始化函数,而没有显示调用父类的初始化函数,则父类的属性不会被初始化。
class Parent(object):
def __init__(self, data):
self.data = data
print "create an instance of:", self.__class__.__name__
print "data attribute is:", self.data class Child(Parent):
def __init__(self):
print "call __init__ from Child class" c = Child()
print c.data #出错
如果子类定义了自己的初始化函数,显示调用父类,子类和父类的属性都会被初始化
class Parent(object):
def __init__(self, data):
self.data = data
print "create an instance of:", self.__class__.__name__
print "data attribute is:", self.data class Child(Parent):
def __init__(self):
print "call __init__ from Child class"
super(Child, self).__init__("data from Child") c = Child()
print c.data
2)super
在子类中,一般会定义与父类相同的属性(数据属性,方法),从而来实现子类特有的行为。也就是说,子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的属性和方法。
class Parent(object):
fooValue = "Hi, Parent foo value"
def foo(self):
print "This is foo from Parent" class Child(Parent):
fooValue = "Hi, Child foo value"
def foo(self):
print "This is foo from Child" c = Child()
c.foo()
print Child.fooValue
在这段代码中,子类的属性”fooValue”和”foo”覆盖了父类的属性,所以子类有了自己的行为。
但是,有时候可能需要在子类中访问父类的一些属性:
class Parent(object):
fooValue = "Hi, Parent foo value"
def foo(self):
print "This is foo from Parent" class Child(Parent):
fooValue = "Hi, Child foo value"
def foo(self):
print "This is foo from Child"
print Parent.fooValue
# use Parent class name and self as an argument
Parent.foo(self) c = Child()
c.foo()
这时候,可以通过父类名直接访问父类的属性,当调用父类的方法是,需要将”self”显示的传递进去的方式。
这种方式有一个不好的地方就是,需要经父类名硬编码到子类中,为了解决这个问题,可以使用Python中的super关键字:
class Parent(object):
fooValue = "Hi, Parent foo value"
def foo(self):
print "This is foo from Parent" class Child(Parent):
fooValue = "Hi, Child foo value"
def foo(self):
print "This is foo from Child"
# use super to access Parent attribute
print super(Child, self).fooValue
super(Child, self).foo() c = Child()
c.foo()
对于”super(Child, self).foo()”可以理解为,首先找到Child的父类Parent,然后调用父类的foo方法,同时将Child的实例self传递给foo方法。
但是,如果当一个子类有多个父类的时候,super会如何工作呢?这是就需要看看MRO的概念了。
3)MRO
假设现在有一个如下的继承结构,首先通过类名显示调用的方式来调用父类的初始化函数:
class A(object):
def __init__(self):
print " ->Enter A"
print " <-Leave A" class B(A):
def __init__(self):
print " -->Enter B"
A.__init__(self)
print " <--Leave B" class C(A):
def __init__(self):
print " --->Enter C"
A.__init__(self)
print " <---Leave C" class D(B, C):
def __init__(self):
print "---->Enter D"
B.__init__(self)
C.__init__(self)
print "<----Leave D"
d = D()
从输出中可以看到,类A的初始化函数被调用了两次,这不是我们想要的结果:
下面,我们通过super方式来调用父类的初始化函数:
class A(object):
def __init__(self):
print " ->Enter A"
print " <-Leave A" class B(A):
def __init__(self):
print " -->Enter B"
super(B, self).__init__(self)
print " <--Leave B" class C(A):
def __init__(self):
print " --->Enter C"
super(C, self).__init__(self)
print " <---Leave C" class D(B, C):
def __init__(self):
print "---->Enter D"
super(D, self).__init__(self
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类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一个父类函数被调用多次
2. __slots__
从前面的介绍可以看到,当我们通过一个类创建了实例之后,仍然可以给实例添加属性,但是这些属性只属于这个实例。
有些时候,我们可以需要限制类实例对象的属性,这时就要用到类中的__slots__属性了。__slots__属性对于一个tuple,只有这个tuple中出现的属性可以被类实例使用。
class Student(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属性的时候,就会遇到异常.
1) 子类没有__slots__属性
使用__slots__要注意,__slots__定义的属性仅对当前类的实例起作用,对继承的子类实例是不起作用的:
class Person(object):
__slots__ = ("name", "age")
pass
class Student(Person):
pass s = Student()
s.name, s.age = "Wilber", 28
s.score = 100
print "%s is %d years old, score is %d" %(s.name, s.age, s.score)
从代码的输出可以看到,子类Student的实例并不受父类中__slots__属性的限制:

2) 子类拥有__slots__属性
但是,如果子类本身也有__slots__属性,子类的属性就是自身的__slots__加上父类的__slots__。
class Person(object):
__slots__ = ("name", "age")
pass
class Student(Person):
__slots__ = ("score", )
pass s = Student() s.name, s.age = "Wilber", 28
s.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学习总结19:类(二)的更多相关文章
- Python学习 Part7:类
Python学习 Part7:类 1. 作用域和命名空间 命名空间(namespace)就是一个从名称到对象的映射. 命名空间的一些实例:内置名称集(函数,像abs(),和内置异常名称),一个模块中的 ...
- python学习笔记4_类和更抽象
python学习笔记4_类和更抽象 一.对象 class 对象主要有三个特性,继承.封装.多态.python的核心. 1.多态.封装.继承 多态,就算不知道变量所引用的类型,还是可以操作对象,根据类型 ...
- 《Python学习手册》(二)
<Python学习手册>(二) --类型和运算 数字 十六进制 八进制 二进制 0x 0o 0b hex() oct() bin() >>>int('10',2) 2 & ...
- 【Python学习之七】类和对象
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 python3.6 一.面向对象编程1.概念(1)面向对象编程(OOP ...
- Python学习笔记 for windows 二
函数 abs(-20) //结果为:20,绝对值函数 def 函数名称([参数1,参数2,参数3]): 执行语句 retu ...
- Python学习笔记 - day7 - 类
类 面向对象最重要的概念就是类(Class)和实例(Instance),比如球类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同.在Python中,定义类 ...
- Python学习总结19:类(一)
在Python中,可以通过class关键字定义自己的类,通过类私有方法“__init__”进行初始化.可以通过自定义的类对象类创建实例对象. class Student(object): count ...
- Python学习【第十二篇】模块(2)
序列化 1.什么是python序列化? 把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling 序列化就是将python的数据类型转换成字符串 反序列化就是将字符串转换成 ...
- python学习笔记系列----(二)控制流
实际开始看这一章节的时候,觉得都不想看了,因为每种语言都会有控制流,感觉好像我不看就会了似的.快速预览的时候,发现了原来还包含了对函数定义的一些描述,重点讲了3种函数形参的定义方法,章节的最后讲述了P ...
随机推荐
- java TimeUnit synchronized demo
import java.util.concurrent.TimeUnit; public class TestCalc { private static boolean stopRequested=f ...
- BLE GATT规范中关于UUID与属性的详细解析
1. 角色 除了GAP定义了角色之外,BLE还定义了另外2种角色:GATT服务器和GATT客户端,它们完全独立于GAP的角色.提供数据的设备称为GATT服务器,访问GATT服务器而获得数据的设备称为G ...
- FW:使用weave管理docker网络
Posted on 2014-11-12 22:20 feisky 阅读(1761) 评论(0) 编辑 收藏 weave简介 Weave creates a virtual network that ...
- 三种查看SqlServer中数据物理pge页的方法
1.根据数据记录查看当前记录所在的文件编号.page页.以及在页中的插槽. 示例如下: SELECT top %%physloc%%, sys.fn_physlocFormatter (%%physl ...
- 【Android开发学习笔记】【第四课】基础控件的学习
通过一个简单的例子来学习下面几种控件: 1.TextView:简单的文本显示控件 2.EditText:可以编辑的文本框 3.Button:按钮 4.Menu:这里指的是系统的Menu 5.Toast ...
- Provisioning Profile
什么是Provisioning Profile? 从字面翻译,Provisioning Profile就是配置文件的意思,它在开发者账号体系中所扮演的角色也是配置和验证的作用.如果你有开发者账号,可以 ...
- 流媒体学习一(RTP)
一.流媒体简介 随着Internet的日益普及,在网络上传输的数据已经不再局限于文字和图形,而是逐渐向声音和视频等多媒体格式过渡.目前在网络上传输音频/视频(Audio/Video,简称A/V)等多媒 ...
- 【C++Q】
//c_str const char* str2Cchar(string s){ //const char* ss = s.c_str(); //出错,因为s会被析构,ss指向垃圾内容 ]; strc ...
- UITableViewCell 设置圆角
#import <QuartzCore/QuartzCore.h> QuartzCore.framework [self.commentsCell.layer setMasksToBoun ...
- ios copy/strong/weak..使用总结
总结 关于属性的这些选项的学习,做一下总结: 所有的属性,都尽可能使用nonatomic,以提高效率,除非真的有必要考虑线程安全. NSString:通常都使用copy,以得到新的内存分配,而不只是原 ...