Python面向对象中的继承、多态和封装
Python面向对象中的继承、多态和封装
一、面向对象的三大特性
- 封装:把很多数据封装到⼀个对象中,把固定功能的代码封装到⼀个代码块, 函数,对象, 打包成模块。 这都属于封装思想。
- 继承:⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容。 说⽩了, ⼉⼦可以随便⽤爹的东⻄。
- 多态: 同⼀个对象, 多种形态。在Python中处处是多态,因为在Python中一个变量可以是多种形态。
二、封装
封装,顾名思义,就是将某些东西给封装起来,以后想要使用的时候再去调用。
所以,在使用面向对象的封装特性时需要:① 将内容封装到某处 ② 调用时从某处取出来
封装分为两部分:
- 广义上的封装:实例化一个对象,给对象空间封装一些属性。
- 狭义上的封装:私有制。私有成员:私有静态属性,私有方法,私有对象属性。
我们先看广义上的封装:
将内容封装到某处
class MyClass:
def __init__(self, name, age):
self.name = name
self.age = age # 在实例化对象时,会自动执行__init__方法,将对象空间传递给self这个位置参数
obj = MyClass("oldniu", 20)
# 将"oldniu" 和 20 分别封装到obj(self)的name和age属性中
从某处调用封装的内容
调用被封装的内容时,有两种方式:① 通过对象直接调用 ② 通过self间接调用
通过对象直接调用
class MyClass:
def __init__(self, name, age):
self.name = name
self.age = age obj = MyClass("oldniu", 20)
print(obj.name) # 通过obj对象直接调用里面的name属性
print(obj.age) # 通过obj对象直接调用里面的age属性
通过self间接调用
class MyClass:
def __init__(self, name, age):
self.name = name
self.age = age def func(self):
print(self.name) # 使用self间接调用obj对象中的name属性
print(self.age) # 使用self间接调用obj对象中的age属性 obj = MyClass("oldniu", 20)
obj.func() # 对象执行方法时Python会默认将obj传给参数self
综上所述,对于面向对象广义上的封装来说,其实就是使用初始化方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
我们再看狭义上的封装
私有静态属性
class MyClass:
__gender = "男" # 私有静态属性 def __init__(self, name, age):
self.name = name
self.age = age def get_gender(self):
return self.__gender # 在类的内部可以访问私有静态属性 # print(MyClass.__gender) # 类名不能直接访问私有静态属性 obj = MyClass("oldniu", 20)
# print(obj.__gneder) # 对象不能访问私有静态属性 print(obj.get_gender()) # 男对于私有静态字段来说,只能在本类中内部访问,类的外部,子类均不可访问。
tips:其实在类的外部可以通过使用_MyClass__gender访问私有静态属性,但是一般我们不会去使用。
私有方法
class MyClass: def __init__(self, name, age):
self.name = name
self.age = age def __func(self):
print("666666") def func(self):
self.__func() 类内部访问静态方法 obj = MyClass("dogfa", 20)
obj.func()
# 私有方法和私有静态字段一样,只能在本类中内部访问,类的外部和子类均不课访问。
三、继承
什么是继承?⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容就是继承。
- 继承的优点
- 提高代码的复用性
- 提高代码的维护性
- 使类与类之间发生关联
- 继承的分类
- 单继承
- 多继承
我们先来看单继承
类名,对象执行父类方法
# 定义一个Animal父类
class Animal:
type_name = "动物类" def __init__(self, name):
self.name = name def eat(self):
print("吃吃吃...") # 继承于Animal类
class Dog(Animal):
pass # 类名调用父类的属性和方法
print(Dog.type_name)
Dog.eat(111) # 对象调用父类的属性和方法
dog = Dog("二哈") # 调用父类的__init__方法实例化对象
print(dog.name)
print(dog.type_name)
dog.eat()
print(dog.__dict__)
执行顺序
- 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
- 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
同时执行类及父类方法
方法一:
如果想执行父类的func方法,这个方法并且子类中夜用,那么就在子类的方法中写上:
父类.func(对象,其他参数)
class Animal:
type_name = "动物类" def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender def eat(self):
print("吃吃吃...") class Bird(Animal):
def __init__(self, name, age, gender, wing):
Animal.__init__(self, name, age, gender) # 执行了父类的__init__方法进行初始化
self.wing = wing # 给对象封装wing属性 obj = Bird("鹦鹉", 3, "雌", "翅膀")
print(obj.__dict__)
# {'name': '鹦鹉', 'age': 3, 'gender': '雌', 'wing': '翅膀'}
方法二:
利用super,super().func(参数)
class Animal:
type_name = "动物类" def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender def eat(self):
print("吃吃吃...") class Bird(Animal):
def __init__(self, name, age, gender, wing):
super().__init__(name, age, gender) # 使用super会自动将self传给父类
self.wing = wing # 给对象封装wing属性 obj = Bird("鹦鹉", 3, "雌", "翅膀")
print(obj.__dict__)
# {'name': '鹦鹉', 'age': 3, 'gender': '雌', 'wing': '翅膀'}
再来看看多继承
在多继承中要补充一点,在这里要注意类的种类。类可以分为经典类和新式类。
新式类:继承object类的类称为新式类。在Python3中默认都是继承object类,所以默认所有类都是新式类。
经典类:不继承object类的类称为经典类。在Python2中默认使用经典类,当然也可以自己手动继承object类来达到变成经典类的目的。
经典类的多继承
在Python的继承体系中, 我们可以把类与类继承关系化成⼀个树形结构的图。
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E:
pass
class F(D, E):
pass
class G(F, D):
pass
class H:
pass
class Foo(H, G):
pass
对付这种mro画图就可以:
继承关系图已经有了,那如何进⾏查找呢? 记住⼀个原则, 在经典类中采⽤的是深度优先遍历⽅案。 什么是深度优先,就是⼀条路走到头, 然后再回来, 继续找下⼀个。
类的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C
新式类的继承
mro序列
MRO是一个有序列表L,在类被创建时就计算出来。
通用计算公式为:mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
(其中Child继承自Base1, Base2)
如果继承至一个基类:class B(A)
这时B的mro序列为mro( B ) = mro( B(A) )
= [B] + merge( mro(A) + [A] )
= [B] + merge( [A] + [A] )
= [B,A]
如果继承至多个基类:class B(A1, A2, A3 …)
这时B的mro序列mro(B) = mro( B(A1, A2, A3 …) )
= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
= ...
计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。
表头和表位
表头:
列表的第一个元素表尾:
列表中表头以外的元素集合(可以为空)示例
列表:[A, B, C]
表头是A,表尾是B和C列表之间的+操作
+操作:
[A] + [B] = [A, B]
(以下的计算中默认省略)
---------------------merge操作示例:
如计算merge( [E,O], [C,E,F,O], [C] )
有三个列表 : ① ② ③ 1 merge不为空,取出第一个列表列表①的表头E,进行判断
各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
2 取出列表②的表头C,进行判断
C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
3 进行下一次新的merge操作 ......
---------------------
计算mro(A)方式:
mro(A) = mro( A(B,C) ) 原式= [A] + merge( mro(B),mro(C),[B,C] ) mro(B) = mro( B(D,E) )
= [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
= [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O]
= [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
= [B,D,E] + merge([O] , [O])
= [B,D,E,O] mro(C) = mro( C(E,F) )
= [C] + merge( mro(E), mro(F), [E,F] )
= [C] + merge( [E,O] , [F,O] , [E,F] )
= [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
= [C,E,F] + merge([O] , [O])
= [C,E,F,O] 原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
= [A,B] + merge( [D,E,O], [C,E,F,O], [C])
= [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
= [A,B,D,C] + merge([E,O], [E,F,O])
= [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
= [A,B,D,C,E,F] + merge([O], [O])
= [A,B,D,C,E,F,O]
---------------------
三、多态
多态:同一个对象,多种形态。
由于Python是弱类型语言, 在定义变量和传参的时候可以是任意形态的值,所以Python默认支持多态。
鸭子类型:你看起来像鸭子,那就是鸭子。
对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。比如list、tuple、str都有index()方法,这就是互称为鸭子类型。
Python面向对象中的继承、多态和封装的更多相关文章
- Python面向对象,析构继承多态
析构: def __del__(self): print("del..run...") r1 = Role("xx") del r1 结果打印del..run. ...
- 47、Python面向对象中的继承有什么特点?
继承的优点: 1.建造系统中的类,避免重复操作. 2.新类经常是基于已经存在的类,这样就可以提升代码的复用程度. 继承的特点: 1.在继承中基类的构造(__init__()方法)不会被自动调用,它需要 ...
- Python面向对象三要素-继承(Inheritance)
Python面向对象三要素-继承(Inheritance) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.继承概述 1>.基本概念 前面我们学习了Python的面向对象三 ...
- JavaScript面向对象中的继承
1.1继承的基本概念 使用一个子类,继承另一个父类,那么子类可以自动拥有父类中的所有属性和方法,这个过程叫做继承. >>>继承的两方,发生在两个类之间. 实现继承的三种方式: 扩展O ...
- Python面向对象中的“私有化”
Python面向对象中的“私有化” Python并不直接支持私有方式,而要靠程序员自己把握在外部进行特性修改的时机. 为了让方法或者特性变为私有(从外部无法访问),只要在它的名字前面加上双下划线即可. ...
- python面向对象中的封装、继承、多态
封装 可以简单的理解为隐藏一切可以隐藏的实现细节,只向外界提供简单的编程接口.我们在类中定义的方法其实就是把数据和数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以 ...
- Python面向对象初始(三大特征,多态,继承,封装)
Python面向对象的初始 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了写程序的 ...
- python oop常用术语 继承 多态 封装
面向对象优点 1.通过封装明确了内外 2.通过继承+多态在语言层面支持了归一化设计 抽象/实现 抽象指对现实世界问题和实体的本质表现,行为和特征建模,建立一个相关的子集,可以用于 绘程序结构,从而实现 ...
- python 面向对象专题(四):封装、多态、鸭子类型、类的约束、super
https://www.cnblogs.com/liubing8/p/11321099.html 目录 Python面向对象04 /封装.多态.鸭子类型.类的约束.super 1. 封装 2. 多态 ...
随机推荐
- Spring框架AOP
aop技术是面向切面编程思想,作为OOP的延续思想添加到企业开发中,用于弥补OOP开发过程中的缺陷而提出的编程思想.AOP底层也是面向对象:只不过面向的不是普通的Object对象,而是特殊的AOP对象 ...
- 图解Linux进程间通信实现原理(1)
为Linux应用程序的开发人员,对Linux的进程间通信方式肯定是了如指掌,平时的开发中应该会大量的使用到.当你迅速的在键盘上按下[CTRL+C]终止掉一个正在运行中的命令时,你有没有仔细的思考过背后 ...
- mongodb 数据更新命令、操作符
一.Mongodb数据更新命令 Mongodb更新有两个命令:update.save. 1.1update命令 update命令格式: db.collection.update(criteria,ob ...
- apt如何列出所有已经安装的软件包
apt如何列出所有已经安装的软件包 转 https://www.helplib.com/ubuntu/article_155294 问题: 我想将所有已安装软件包的列表输出到文本文件中,以便我可以查看 ...
- Maven IntelliJ
IntelliJ IDEA 已经内建了对 Maven 的支持.我们在此例中使用的是 IntelliJ IDEA 社区版 11.1. IntelliJ IDEA 的一些特性列出如下: 可以通过 Inte ...
- 在IIS7、IIS7.5中应用程序池最优配置方案
先介绍几个简单的设置 应用程序池 > 高级设置 1.基本设置 队列长度: 65535 启动32位应用程序 否则安装一些32的组建或32位的php都会出错 托管管道模式 Classsic 2.高级 ...
- (翻译) closures-are-not-complicated
总计:读完这篇文章需要20分钟 这篇文章讲解了闭包的一些内容,作者是拿ES5规范中的一些名词来讲的. 所以可能和博客上一篇文章中提到的binding object, (lexical enviro ...
- PostgreSQL 之 CREATE FUNCTION
官方文档 语法: CREATE [ OR REPLACE ] FUNCTION name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } d ...
- spring 使用@Valid校验数据出错DEBUG org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod - Failed to resolve argument 0 of type
问题原因:在 @Valid 的那个参数后面紧跟着一个 BindingResult 的参数(一定要紧跟着) 参考来源:https://segmentfault.com/q/101000000838468 ...
- 100% 加速 WebSAMS 3.0 (轉載)
今日已經是WebSAMS Upgrade 的最後一日,已經有99.8% 學校成功upgrade WebSAMS 3.0.但有學校向我們反映WebSAMS 3.0 比2.0 慢,經過我們的Enginee ...