Python 中的继承、多态和封装
涉及问题:
Python 中如何实现多继承,会有什么问题?
Python 中的多态与静态方法有什么区别?
答案要点如下:
- Python 中的继承,就是在定义类时,在括号中声明父类,简单示例如下:
class Father(object): # object 是最基础的一个类,和 JAVA 中的 Object 是一样的
pass
class Chile(Father): # 继承 Father 类
pass
- 我们都知道,在定义类时,可以通过定义 __init__ 方法来初始化类的属性。有点类似于 JAVA 中的有参构造。但不同的是,在 JAVA 中,子类的构造函数会默认调用父类的无参构造,即在构造函数中的无论你写与不写,第一句代码都是 super() 。而在 Python 中不是的,如果子类不重写 __init__ 方法,默认会调用父类的 __init__ 。而一旦子类自己定义了 __init__,则不再会调用父类中的方法,如果想调用,需要手动通过 super() 来调用。示例代码如下:
class Father(object):
f_out = "123"
def __init__(self, f):
print("father class")
self.f = f
class Child_1(Father):
pass
class Child_2(Father):
# 如果子类中不重写 __init__ 方法,会默认调用父类中的 __init__ 方法
# 但是如果重写后,则不会自动调用父类中的 __init__ 方法,需要手动来调用
def __init__(self):
# 如果子类在初始化参数时,没有父类的参数,则子类不再有父类拥有的实例属性
# 但类属性仍然会被继承
print("child class")
print(self.f_out)
# 如果想调用父类
# super(Child_2, self).__init__("123")
# c1 = Child_1() # 如果不传参会报错说接受一个参数,这里就已经说明在调用父类的 __init__
c1 = Child_1("123") # 输出 father class,且必须传入一个参数
print(c1.f) # 得到 123
c2 = Child_2() # 不接受参数,因为子类中没有参数
# 输出 child class 123
# print(c2.f) # 报错,找不到 attribute f
- super() 方法的说明,第一个参数是当前类,即子类,第二个参数固定 self,表示当前的实例对象,在 Python2 中必须加参数调用,而 python3 中可以省略参数,如下所示:
# python2
super(Child, self).父类方法(*args, **kw)
# python3
super().父类方法(*args, **kw)
- Python 相比于 JAVA 更好的一点在于支持多继承,而 JAVA 是单一继承的。在 JAVA 中实现多继承可以通过接口与内部类(这也是我曾经遇到过的一个面试题,有兴趣的可以自行查找资料)。在 Python 实现多继承就很简单了,示例如下:
class Father():
pass
class Mother():
pass
class Child(Father, Mother):
pass
- 需要注意的是,在 Python 中多继承的调用会存在一些问题,有时候会出现我们意想不到的结果,这里不详细展开,感兴趣的可以自己了解,后面会再开文章进行介绍。主要示例代码如下:
class Base(object):
def __init__(self):
print("enter base")
print('leave base')
class A(Base):
def __init__(self):
print('enter A')
super(A, self).__init__()
print('leave A')
class B(Base):
def __init__(self):
print('enter B')
super(B, self).__init__()
print('leave B')
class C(A,B):
def __init__(self):
print('enter C')
super(C, self).__init__()
print('leave C')
c = C()
# 输出结果如下
‘’‘
enter C
enter A
enter B
enter base
leave base
leave B
leave A
leave C
’‘’
- Python 中的封装。主要是对属性的封装,采用 __属性名 的形式,(注意是两个下划线)。在 Python 中,以两个下划线开头和结尾,是 Python 中的一些特殊变量,所以我们在私有化属性时,一般不这样定义。而以一个下划线开头的属性,可以通过 实例名. 的方式进行调用,但它有个约定俗成的含义,即:我可以通过 实例. 来调用,但请把我视为 私有变量。(这也很符合 Python 中体现的一切靠自觉的思想)。示例如下:
class Test(object):
def __init__(self, name, age, sex):
self.__name = name
self._age = age
self.sex = sex
t = Test("Demon", 18, 'M')
# print(t.__name) # 'Test' object has no attribute '__name'
print(t._Test__name) # 可以这样访问到,但不要这样做
print(t._age) # 18
print(t.sex) # M
- Python 中的多态。在 JAVA 中,用一句话总结多态就是 父类引用指向子类对象。而在 Python 中,父类引用指向子类对象也是多态的一种实现,但不同的是 Python 中多了一种鸭子类型,即如果一个动物,叫起来像鸭子,走起来像鸭子,跑起来像鸭子,那我们就认为它是一只鸭子。即如果一个类,它有和别的类相同的方法,我们就认为它和这个类具有某种关系,是类似的一种类。示例如下:
class Animal(object):
def run(self):
print('Animal run')
# 定义一个 Animal 的子类
class Dog(Animal):
def run(self):
print('Dog run')
# 定义一个类似 Animal 的类
class Like_Animal(object):
# 同样具有 run() 方法
def run(self):
print('I can run too!!!')
# 定义一个方法,参数是实例对象 ,根据参数来调用对应的 run() 方法
# 也就是我们说的多态
def start_run(run_obj):
run_obj.run()
# 传入一个 Animal 实例对象
start_run(Animal())
# 传入一个 Dog 实例对象
start_run(Dog())
# 传入一个 类Animal 实例对象
start_run(Like_Animal())
扩展:
- 关于多继承,涉及到 Python 中的 MRO ,后面会再详细介绍
- 关于封装,还可以使用 @property ,这个也比较常用,可以自己了解下
- http://www.aibbt.com/a/22236.html
Python 中的继承、多态和封装的更多相关文章
- python面向对象之继承/多态/封装
老师说,按继承/多态/封装这个顺序来讲. 子类使用父类的方法: #!/usr/bin/env python # coding:utf-8 class Vehicle: def __init__(sel ...
- python中的继承和多态
继承 继承的表现方式: class Animal(): pass class Cat(Animal): #animal是cat的父类,也可以说是基类 pass print(Cat.__bases__) ...
- python中的继承原则
继承是面向对象的重要特征之一,继承是两个类或者多个类之间的父子关系,子进程继承了父进程的所有公有实例变量和方法.继承实现了代码的重用.重用已经存在的数据和行为,减少代码的重新编写,python在类名 ...
- Python中的继承
继承: 面向对象程序语言的一个重要特点是继承.继承提供了在已存在类的基础上创建新类的方法.继承的子类 拥有被继承的父类的所有方法,在此基础上,子类还可以添加自己的专有方法.继承是类的强有力的特点.一些 ...
- python中多继承C3算法研究
在python的面向对象继承问题中,单继承简单易懂,全部接受传承类的属性,并可添加自带属性, 但是,在多继承情况下,会遇到多个被继承者的顺序问题,以及多次继承后查找前几次继承者需求属性时,可能不易发现 ...
- Python之浅谈多态和封装
目录 组合 什么是组合 为什么使用组合 多态和多态性 多态 什么是多态? 多态性 好处 多态性 什么是多态性 封装 封装是什么意思? 隐藏 如何用代码实现隐藏 python 实际上是可以访问隐藏属性的 ...
- python中 的继承
1.Python的类可以继承多个类,Java和C#中则只能继承一个类. 2.Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先. 当类是经典类时,多继承情况下,会 ...
- Python 中 对logging 模块进行封装,记录bug日志、日志等级
是程序产生的日志 程序员自定义设置的 收集器和渠道级别那个高就以那个级别输出 日志和报告的作用: 报告的重点在于执行结果(执行成功失败,多少用例覆盖),返回结果 日志的重点在执行过程当中,异常点,哪里 ...
- 理解Python中的继承规则和继承顺序
先来看一段代码: class First(object): def __init__(self): print ("first") class Second(object): de ...
随机推荐
- 聊聊JavaScript-闭包
今天聊聊闭包,网上五花八门的定义和解释很多很多,是不是搞得你很懵逼:每次看闭包,都不同,本来自己懂,看完别人的之后就开始怀疑自己了.在我看来,闭包简单的说就是函数里面套函数,再往大了说就是我函数外面想 ...
- postman 中调试接口的小记录
1.form-data: 就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开.既可以上传键值对,也可以上传文件.当上传的字段是文件 ...
- ES6的介绍和常用语法
本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. 前言 ECMAScript 是 JS 的语言标准.而 ES6 是新的 J ...
- C# 之三类文件的读写( .XML,.INI 和 .TXT 文件)
笔记之用,关于三类.xml, .ini, .txt 文件的 C# 读写,请多多指教! 1,第一类:.xml 文件的读写 先贴上xml文件,下面对这个文件进行操作: <?xml version=& ...
- Shell脚本——特殊符号
1. # 井号(pound) 脚本文件运行时,使用的解释器. #!/bin/sh 其他时候表示注释. # This is a comment. 2. ~ 波浪号(tilde) 表示当前用户使用的hom ...
- JSP标签c:forEach报错(一)
1.jsp标签c:forEach报错,具体错误如下: 三月 31, 2014 9:31:14 下午 org.apache.catalina.core.StandardWrapperValve invo ...
- 图像处理------泛洪填充算法(Flood Fill Algorithm) 油漆桶功能
泛洪填充算法(Flood Fill Algorithm) 泛洪填充算法又称洪水填充算法是在很多图形绘制软件中常用的填充算法,最熟悉不过就是 windows paint的油漆桶功能.算法的原理很简单,就 ...
- OpenGL结合C#进行绘图
转自:http://www.cnblogs.com/wangshide/archive/2012/04/14/2447499.html 本人对OpenGL产生了浓厚的兴趣,又想学习一下C#这个语言,就 ...
- 错误号:1364 错误信息:Field 'platId' doesn't have a default value
1. 错误描述 错误号:1364 错误信息:Field 'platId' doesn't have a default value insert into `use`.`t_platform_scal ...
- vxWorks下intel82567v3网卡驱动的更新
/* 82567 devicesID */ #define INTEL_DEVICEID_82567LF 0x10BF#define INTEL_DEVICEID_82567 ...