面向对象的三大特征:封装、继承、多态。

封装

封装是面向对象编程的一大特点,将属性和方法放到类的内部,通过对象访问属性或者方法,隐藏功能的实现细节,也可以设置访问权限。

class Student():def __init__(self,name,age):self.name = name     # 将属性封装到类的内部self.age = agedef prin_info(self):print(self.name,self.age)# 在同一个类创建多个对象之间,属性是互不干扰的
zs = Student('张三', 20)
ls = Student('李四',21)
zs.prin_info()
ls.prin_info()

继承(重点)

继承是一种创建新类的方式,如果子类需要复用父类的属性或者方法时,就可以使用继承。当然,子类也可以提供自己的属性和方法。
父类中已经有的方法,在子类中直接继承,不用再重写。避免重复造轮子,减少代码的冗余。

class Father():     # 父类 超类pass
class Son(Father):  # 子类 派生类pass

注意:在 python 中,新建的类可以继承一个或多个父类
继承作用:避免重复造轮子,减少代码的冗余

新式类与经典类

在 Python2 当中类分为新式类和经典类,如果有继承父类 object 则是新式类,否则为经典类。

class Test():       # 在python2中,经典类passclass Test1(object):    #继承了object,在python2中,新式类passTest()
Test1()

但是在 Python3 当中,全部都是新式类,默认继承 object
练习:验证 Python3 中,全部都是新式类
实现思路:比较继承与无继承两个空类的成员是否一致
拓展方法:对象.dir() 查看对象的属性与方法

class Test():       # 在python2中,经典类passclass Test1(object):    #继承了object,在python2中,新式类passd1 = Test()
d2 = Test1()
print(len(d1.__dir__()),d1.__dir__())  # 26个,两者方法完全一致
print(len(d2.__dir__()),d2.__dir__())  # 26个,两者方法完全一致

在object类中有很多的魔法方法,如init、str等等,创建的类直接继承了object类,可以使用object所有的方法。

单继承

从继承几个父类来划分,可以分为单继承和多继承
子类继承父类,则可以直接享受父类中已经封装好的方法
练习:用代码实现如下

实现代码如下

class Grandfather(object):def sleep(self):print('Grandfather sleep 11')class Father(Grandfather):def eat(self):print('Father eat')def drink(self):print('Father drink')class Son(Father):def study_python(self):print('Son study_python')def sleep(self):print('Son sleep 8')   # 当子类中有与父类名字相同的方法,就意味着对父类方法进行了重写T = Son()
T.study_python()  # 自己的方法可以直接使用
T.eat()     # 通过子类的对象可以使用父类的方法, 子类中没有的,可以从父类中找
T.sleep()   # 子类中有就使用子类的方法;子类没有,去父类中找,父类中没有,则继续去父类的父类中去找

当对象调用方法时,查找顺序先从自身类找,如果自身没找到,则去父类找,父类无,再到父类的父类找,直到object类,若还无,则报错。这也称为深度优先机制

需要注意的是,当子类与父类拥有同名称的方法时,子类对象调用该方法优先执行自身的方法。那么实际上就是子类的方法覆盖父类的方法,也称为重写。
但是实际的开发中,遵循开放封闭原则。我们并不会完全的重写父类的方法,而是希望同时实现父类的功能。这时,我们就需要调用父类的方法了,可以通过 super()函数实现。

super()

super(type[, object-or-type]) 函数是用于调用父类(超类)的一个方法
type --> 类
object-or-type --> 对象或类,一般是 self
练习:继以上练习实现,在Son的sleep方法当中,调用父类的sleep方法。

class Grandfather(object):def sleep(self):print('Grandfather sleep 11')class Father(Grandfather):passclass Son(Father):def study_python(self):print('Son study_python')def sleep(self):print('Son sleep 8')# 在执行自己的方法的时候,仍然继承父类的方法# super(Son, self).sleep()    # 两个sleep的方法都会被调用,通过Son对象去调用父类的sleep方法# super().sleep()     # 两个sleep的方法都会被调用,参数不写也可以Grandfather.sleep(self) # 通过 类名.方法名(self),必须写self,self是当前T的对象,去调用了sleep# 不管在子类还是父类,self永远都是指当前实例化T的对象T = Son()
T.sleep()

总结:
1.单继承:深度优先,先从自己找,再往父类找,然后是父类的父类找,最终的父类是object类,没有的话就报错
2.重写: 防止执行父类当中的方法
3.self永远指的都是执行该方法的调用者
4.super(当前类,self).父类中的方法

注意:
1.__init__方法也会继承,同实例方法一致,深度优先

class Father(object):def __init__(self):print('Father')class Son(Father):pass# 如果自己有__init__方法,则会重写,深度优先
T = Son()   # Fther

2.私有属性以及私有方法没有被继承

class Father(object):def __init__(self):self.name = '张三'self.__age = 20def test(self):print('test')def __test2(self):print('__test2')class Son(Father):def get_test(self):print(self.name)  # 张三# 私有属性不会被继承# print(self.__age)   # 报错 '_Son__age' Son类中没有__age属性self.test()     # test# 私有方法也不会被继承self.__test2    # 报错,'_Son__test2' Son类中没有__test2方法T = Son()
T.get_test()

多继承

所谓多继承,即子类有多个父类,并且具有它们的特征(属性和方法),JAVA和C#不支持多继承,无法判断子类继承时,调用哪一个类的相同的方法。

情景1

Son类继承Father类和Father1类,两个父类均有run方法,应该继承哪一个呢?遵循左边优先的原则

class Father(object):def run(self):    # 实例方法print('Father can run')class Father1(object):def run(self):print('Father1 can run')class Son(Father, Father1):passT = Son()
T.run()     # Father can run  左侧优先

同时继承多个类时,写在括号左侧的类优先被继承。

情景2

Son类继承Father类和Father1类两个父类,Father类继承GrandFather类,Father1和GrandFather类中均有 sleep方法,那么用Son类去调用sleep方法时,应该继承哪一个?遵循左边一条路走到底的原则

class GrandFather(object):def sleep(self):print('GrandFather sleep')class Father(GrandFather):def run(self):    # 实例方法print('Father can run')class Father1(object):def run(self):print('Father1 can run')def sleep(self):print('Father1 sleep')class Son(Father, Father1):passT = Son()
T.sleep()     # GrandFather sleep 左边一条路走到底

情景3

Son类继承Father类和Father1类两个父类,Father类和Father1类又同时继承GrandFather类,Father1类和GrandFather类均有sleep方法,那么用Son类去调用sleep方法时,应该继承哪一个?
遵循左边优先,根(同一个父类)最后执行的原则

class GrandFather(object):def sleep(self):print('GrandFather sleep')class Father(GrandFather):def run(self):    # 实例方法print('Father can run')class Father1(GrandFather):def run(self):print('Father1 can run')def sleep(self):print('Father1 sleep')class Son(Father, Father1):passT = Son()
T.sleep()     # Father1 sleep 两个类有同一个根的时候,根最后执行,Father1 进行了重写父类的方法

总结多继承

python支持多继承,遵循以下原则:1.左边优先,2.一条道路走到底,3.同一个根时,根最后执行。可以通过 (类名.mro ) 方法查看代码的执行顺序。

print(Son.__mro__)  # 基于C3算法
# (<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Father1'>, <class '__main__.GrandFather'>, <class 'object'>)

多态

python是动态语言,具有多态的特征。
多态的概念是应用于 Java 和 C# 这一类强类型语言中,而 Python 崇尚"鸭子类型"
动态语言调用实例方法时不检查类型,只要方法存在,参数正确,就可以调用。
这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态。

class Person(object):def print_self(self):print('自我介绍')class Man(Person):def print_self(self):print('Man的自我介绍')def print_self(obj):obj.print_self()zs = Person()
zs.print_self()  # 自我介绍
print_self(zs)   # 自我介绍  通过函数传参,调用类ls = Man()
ls.print_self()  # Man的自我介绍
print_self(ls)   # Man的自我介绍

一个函数实现了多个不同类方法的调用。不同功能的函数使用相同功能的函数名,就可以用函数名调用不同功能的函数。Person和Man中的print_self实现的功能不一样,可以用一个函数名去调用不同功能的方法,体现出来了多态的含义。

魔法方法介绍

在Python中,有一些内置好的特定方法,这些方法在进行特定的操作时会自动被调用,称为魔法方法。每一个魔法方法都有特定的功能,遇到特定的场景就会被访问,被调用。
魔法方法的命名总是被双下划线包围,比如__名称__

常用魔法方法

1__doc__ :用来查看类的说明文档

查看列表类的说明文档
class list(object):"""list() -> new empty listlist(iterable) -> new list initialized from iterable's items"""
从说明文档中看到,列表也是类。
list()   # 创建列表对象的过程
print(list().__doc__)
输出的结果:
list() -> new empty list
list(iterable) -> new list initialized from iterable's itemsli = list('abc')   # 其实就是实例化的过程,被赋值的变量也是对象。
print(li.__doc__)
运行的结果为:
list() -> new empty list
list(iterable) -> new list initialized from iterable's itemss = '12'
print(s.__doc__)
运行的结果为:
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str

自己定义类的魔法属性,也可以用说明文档__doc__查看,默认继承了object类。

class Test():'''我是注释'''passdis = Test()
print(dis.__doc__)      # 我是注释print(dis.__module__)   #  __main__  当前类所在的模块
print(Test.__class__)   # <class 'type'> 类的类型,Test是type的对象,需要查阅type元类的资料
print(dis.__class__)    # <class '__main__.Test'> dis是Test的对象

2__dict__:用于获取类或者实例的属性字典
注意:
1.实例属性存储在对象中,所以通过 对象__dict__ 获取的是实例属性
2.除实例属性以外的成员都存储在类中,所以通过 类__dict__ 来获取

class Test():country = '中国'def __init__(self):self.name = 'zhang'self.__age = 18def test(self):self.gender = 'male'print('test')dis = Test()
dis.test()  # test
print(dis.__dict__)     # 字典,{'name': 'zhang', '_Test__age': 18, 'gender': 'male'}
# 通过对象去访问,只能访问到存储在对象中的成员(实例属性),实例方法、静态方法、类方法、类属性都存放在类中。
print(Test.__dict__)    # 字典,类名去访问,就可以访问到存储在类当中的成员(除了实例属性之外的属性与方法)
print(dis.__dir__())    # 列表,类中所有的成员,__dict__更倾向于是__dir__()的子集

3__del__():叫做析构方法。当由该类创建的实例对象,被删除或者说在内存中被释放,将会自动触发执行。
总结:
1.当代码全部执行完毕才自动触发__del__()
2.如果需要提前触发,则需要通过del关键字,删除所有对象后触发__del__()

class Test():def __del__(self):print('我被回收了')dis = Test()
print('--'*10)
print('--'*10)
# 在此处触发del,在所有的代码都执行完毕之后,才会执行__del__方法

运行的结果是:

--------------------
--------------------
我被回收了

如果在执行前加入了del,通过关键字 del 将对象删除,则会主动的执行__del__方法

class Test():def __del__(self):print('我被回收了')dis = Test()
print('--'*10)
del dis         # 在此处触发 del
print('--'*10)运行的结果是:
--------------------
我被回收了
--------------------
class Test():def __del__(self):print('我被回收了')dis = Test()   # dis 指向 类的内存地址
d1 = dis      # d1 也同时指向了类的内存地址
print('--'*10)
del dis
print('--'*10)
# 在结尾处触发 del,d1还是指向类的内存地址,仍然存在
# 只有当对象全部释放后,才会触发__del__
'''
注意:
1.不需要重写del方法,重写后就没有实际的意思,只能打印
2.python使用过程中并不需要关心内存的分配和释放,python解释器会有自动的垃圾回收机制,
我们并不需要主动的封装__del__()
若在del dis 处 同时删除 d1,则对象被完全删除了,在此处触发__del__
'''

注意:
此方法一般不需要定义,因为 Python 是一门高级语言,程序员在使用时无需关心内存的分配与释放,一般都是交给 Python 解释器来执行。所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行。
5__call__():用于将对象变成一个可调用的对象。也就是说,当一个类中有__call__()方法时,其实例化得到的对象便是可调用的(callable)

class Test():def __init__(self):print('aaa')dis = Test()
dis()       # 相当于Test()(),TypeError: 'Test' object is not callable

使用或者重写__call__()方法可以让对象变成可以调用的

class Test():def __init__(self):print('aaa')def __call__(self, *args, **kwargs):print('我可以调用')dis = Test()
dis()      # aaa# 我可以调用

6__new__():用于创建与返回一个对象。在类准备将自身实例化时调用。

class Test1(object):def __init__(self):print('__init__')def __new__(cls, *args, **kwargs):  # args是位置参数,kwargs是关键字参数# 重写了父类的new方法,覆盖了之前的方法,对象并未创建成功,不会再触发__init__方法print('__new__')T = Test1()      # __new__  调用对象的时候自动执行__new__
class A(object):def test(self):print('创建对象')class B(A):def test(self):print('重写方法')T = B()
T.test()    # 重写方法,重写后进行了覆盖

注意:
1__new__() 方法用于创建对象,并进行返回
2__init__() 方法在创建对象之后,自动调用执行的方法
3__new__(),重写了父类的__new__() 方法,覆盖了父类__new__() 创建对象的功能,所以对象并没有创建成功,就不会执行__init__() 方法,所以仅执行__new__() 方法内部代码。
对象创建执行顺序
1.通过__new__() 方法 创建对象
2.并将 对象返回,传给__init__()

在自定义类中实现创建对象
class Test1(object):def __init__(self):print('__init__')def __new__(cls, *args, **kwargs):print('__new__')# super().__new__(cls)    # 执行了父类创建对象的代码,没有将创建的代码返回除了,没有自动执行__init__,传入cls代表当前的类return super().__new__(cls)     # 将创建的对象返回出去,自动执行__init__方法T = Test1()  # __new__   __init__

思路:
1.重写父类__new__() 方法
2.并且在该方法内部,调用父类的__new__() 方法
注意:
1.在创建对象时,一定要将对象返回,才会自动触发__init__()方法
2__init__()方法当中的self,实际上就是__new__返回的实例,也就是该对象

3__init__实例方法,__new__静态方法
4__init__在对象创建后自动调用,__new__创建对象的方法

单例模式介绍

单例模式是一种常用的软件设计模式。也就是说该类只包含一个实例。
通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
通常应用在一些资源管理器中,比如日志记录等。

class Single_1(object):def __new__(cls, *args, **kwargs):return super().__new__(cls)   # 重写了new方法,需要调用父类创建对象的方法,然后要返回出去S1 = Single_1()
S2 = Single_1()
print(id(S1))       # 3066933048768
print(id(S2))       # 3066933048264

实例化两个对象后,他们的内存地址不一样,实例多个对象,每个的内存地址也均不相同,并非单例模式。

单例模式实现

思路
1.当对象不存在时,创建对象
2.当对象存在时,永远返回当前已经创建对象,如果不重写创建对象的方法,就不能实现。

class Single_1(object):__isinstance = None       # 1.类属性,建立标识def __new__(cls, *args, **kwargs):if cls.__isinstance is None:  # 通过类对象可以访问到类属性,None代表当前没有创建类对象# 当对象不存在的时候,创建对象,并进行返回# return super().__new__(cls)# 当类属性为None的时候,创建对象赋值给当前的类属性# 2.将一个对象存储到__instance类属性中,此时__instance不为None,就不会再执行if语句cls.__isinstance = super().__new__(cls)   # 创建类属性# 3.返回cls.__instance,也就是创建的对象return cls.__isinstanceelse:# 4.__instance不为None,意味着已经存储着一个对象,直接进行返回return cls.__isinstanceS1 = Single_1()
S2 = Single_1()
S3 = Single_1()
print(id(S1))       # 2495110149232
print(id(S2))       # 2495110149232
print(id(S3))       # 2495110149232

python语言基础(十三)面向对象编程(封装、继承、多态)相关推荐

  1. 面向对象编程 封装 继承 多态(三大特征)(第三篇)

    封装 封装是面向对象编程的三大特征之一. 封装有两方面的含义: 1.将数据(属性)和行为(方法)包装到类对象中.方法内部对属性进行操作,在类对象的外部调用方法.这样,无需关心方法内部的具体实现细节,从 ...

  2. 【Python】Python语言学习:面向对象编程,类和对象,封装、继承和多态

    这一周Python语言学习,记录如下. 01 面向对象编OOP 1.1 为什么学习和应用OOP? 1 OOP适合更加复杂的需求分析和项目开发. 2 OOP具有更强大的封装能力. 3 OOP相比于面向过 ...

  3. 【Java语言基础】面向对象之封装、继承、抽象类、接口、多态综合知识习题及总结day11

    这几天逐渐被idea所折服,越来越喜欢这个优雅又强大的代码编辑器,有很多人说idea对很多初学者不友好,但是在我看来,只要你足够自律,并且英语不会太差,语法上关键的几个单词没什么大问题,idea对初学 ...

  4. python面向对象语言_Python语言基础之——面向对象编程

    1.类属性 1)类属性: 直接定义在类中的变量是类属性 类属性的值不会因为对象不同而不一样 2)对象属性 通过 self.属性名 = 值 定义在init函数中的属性 对象属性的值会因为对象不同而不一样 ...

  5. 【Python】类与对象:封装/继承/多态

    在python中如何将一些功能借鉴及实现? python模块的迁移调用?感觉还是没有形成系统化的构建? 在学习C++的时候,来了一丝灵感,python的重点不是也是类和对象吗? 本人实践python项 ...

  6. C++基础:C++的封装/继承/多态

    封装(encapsulation):封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成"类",其中数据和函数都是 ...

  7. c语言编程 菲薄拉,C语言设计模式-封装-继承-多态

    快过年了,手头的工作慢慢也就少了,所以,研究技术的时间就多了很多时间,前些天在CSDN一博客看到有大牛在讨论C的设计模式,正好看到了,我也有兴趣转发,修改,研究一下. 记得读大学的时候,老师就告诉我们 ...

  8. python面向对象编程(封装与继承)

    一. 面向过程编程语言 "面向过程"(Procedure Oriented)是一种以过程为中心的编程思想.分析出解决问题所需要的步 骤,然后用函数把这些步骤一步一步实现,使用的时候 ...

  9. python面向对象编程 -- 封装、继承

    面向对象编程 -- 封装.继承 面向对象编程三要素:封装.继承和多态.本文主要看和封装.继承相关的概念:在python中多态的概念比较模糊,本文不做讨论. 1 封装 封装:将数据和操作组装到一起,对外 ...

  10. 第二章(1):Python入门:语法基础、面向对象编程和常用库介绍

    第二章(1):Python入门:语法基础.面向对象编程和常用库介绍 目录 第二章(1):Python入门:语法基础.面向对象编程和常用库介绍 1. Python 简介 1.1 Python 是什么? ...

最新文章

  1. 模板元编程时的参数推导类型输出
  2. js文件里获取路由 vue_「如何优雅的使用Vue?」不可不知的Vue实战技巧
  3. 网站文章中如何设置关键词才更有利于SEO优化?
  4. jdbc mysql 函数 慢_java jdbc addBatch()提交mysql速度过慢
  5. WPF中读取txt文件并让其在RichTextBox中显示
  6. java项目教训_[免费电子书]分析超过600,000个Java项目的经验教训
  7. apache和mysql 403_如何使用mysql(lamp)分离环境搭建dedecms织梦网站及apache服务器常见的403http状态码及其解决方法...
  8. Android Studio(4)---开发人员工作流程基础
  9. numpy教程:随机数模块numpy.random
  10. 分页内存与非分页内存导致的蓝屏死机问题
  11. 2020年最新人事管理软件排名(建议收藏)!
  12. x5maxl l android 6,Hi-Fi新纪元 4.75mm超薄vivo X5Max首测
  13. Android TextView动态设置字体颜色选择器
  14. RGB、HSL、Hex网页色彩码,看完这篇全懂了
  15. 美国计算机专业nlp大学排名,美国人工智能专业排名前7的一流学府 看看哪所院校最令你心动吧!...
  16. 【C语言练习——打印空心三角形】
  17. JS addEventListener()方法
  18. 微信小程序 vant-weapp 实现多选标签
  19. 你对国外问卷调查有多少了解?
  20. CSS-div水平居左-居右-居中显示

热门文章

  1. apache knox_如何在兼容的三星手机上设置Knox安全性
  2. dephi FillChar 的几种写法
  3. 计算机组成原理基础: 图灵机与冯诺依曼结构
  4. js验证前台验证用户名只能是汉字
  5. 【JS】判断用户输入的用户名首位是否是字母
  6. Edge-perserving tech
  7. matlab标量或矩阵比较
  8. python 解压rar文件
  9. EFCore反向工程
  10. ComboBox绑定数据源时触发SelectedIndexChanged事件的处理办法