Python 基础 面向对象之二 三大特性

上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员、成员修饰符 面向对象的三大特性:继承、多态和封装,貌似今天内容挺多的,没有关系,慢慢来!

一、类中的基本知识:

一、类的成员、成员修饰符

        一、字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,

  • 普通字段属于对象
  • 静态字段属于类
  1. class Room:
  2. tag=1
  3. def __init__(self,name,owner,width,length,heigh):
  4. self.name=name
  5. self.owner=owner
  6. self.width=width
  7. self.length=length
  8. self.heigh=heigh
  9.  
  10. r1=Room('厕所','sb',100,100,100000)
  11. print(r1.name) # 访问的是普通字段
  12. print(Room.tag) # #直接访问静态字段

so,通过上述例子可以看出:

  • 静态字段在内存中只保存一份
  • 普通字段在每个对象中都要保存一份(相当于绑定在每个实例化对象的身上,然后本身有一个类“指针”的东西指向类)

应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段

    二、方法

方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

  • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self
  • 类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls
  • 静态方法:由调用;无默认参数;
  1. class Foo:
  2.  
  3. def __init__(self, name):
  4. self.name = name
  5.  
  6. def ord_func(self):
  7. """ 定义普通方法,至少有一个self参数 """
  8.  
  9. # print self.name
  10. print ('普通方法')
  11.  
  12. @classmethod
  13. def class_func(cls):
  14. """ 定义类方法,至少有一个cls参数 """
  15.  
  16. print ('类方法')
  17.  
  18. @staticmethod
  19. def static_func():
  20. """ 定义静态方法 ,无默认参数"""
  21.  
  22. print ('静态方法')
  23.  
  24. # 调用普通方法
  25. f = Foo('sb')
  26. f.ord_func()
  27.  
  28. # # 调用类方法
  29. Foo.class_func()
  30. f.class_func()
  31. #
  32. # # 调用静态方法
  33. Foo.static_func()
  34. f.static_func()

类方法调用和静态方法调用的时候既可以使用使用类名调用,也可以使用对象来调用,区别在哪里呢?注意:最大的区别是用类名调用的时候是不需要实例化的,而使用对象来访问时是先要进行实例化,之后再进行调用。

三、属性  

如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。

对于属性,有以下三个知识点:

  • 属性的基本使用
  • 属性的两种定义方式
  1. class Goods:
  2. @property
  3. def pricr(self):
  4. #print('nijiushidahbi')
  5. return "haishininiubi"
  6.  
  7. obj = Goods()
  8. result = obj.pricr
  9. print(result)
  10.  
  11. 显示结果:haishininiubi

由属性的定义和调用要注意一下几点:

  • 定义时,在普通方法的基础上添加 @property 装饰器;
  • 定义时,属性仅有一个self参数
  • 调用时,无需括号
               方法:foo_obj.func()
               属性:foo_obj.prop

注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象

属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回

二、面向对象编程的三大特性介绍

1.继承与派生

继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类。

python中类的继承分为:单继承和多继承

  1. class Grandfather:
  2. pass
  3.  
  4. class Father(Grandfather): #单继承 Father是派生类,grandfather 是基类
  5. pass
  6.  
  7. class son(Father,Grandfather): #多继承
  8. pass

继承使用产生的场景:如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时我们不可能从头开始写一个类B,这就用到了类的继承的概念。通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用。

除了继承与派生的概念还有一个概念是需要提出的那就是:组合。组合就是指在一个类中以另外一个类的对象作为数据属性,成为类的组合。

组合与继承两者到底什么的关系?1.继承的方式:通过继承建立了派生类与基类的关系,两者之间是“是”的关系。当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师    2.组合的方式:用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程(当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好

  1. class School:
  2. def __init__(self,name,addr):
  3. self.name=name
  4. self.addr=addr
  5.  
  6. def zhao_sheng(self):
  7. print('%s 正在招生' %self.name)
  8.  
  9. class Course:
  10. def __init__(self,name,price,period,school):
  11. self.name=name
  12. self.price=price
  13. self.period=period
  14. self.school=school
  15.  
  16. s1=School('北大','北京')
  17.  
  18. c1=Course('linux',10,'1h',s1)
  19. print(c1.name) #linux
  20. print(c1.school) # <__main__.School object at 0x02182330>
  21. print(c1.school.name) # 北大
  22. print(c1.school.addr) # 北京

在这个例子中呢,创建了两个类,一个是学校类一个是课程类。需要将课程类与学校类进行相关联的时候,继承在这里是不合适的,那我们采用组合的方式来对这两个类进行关联,这样就在实例化一门课程的时候把学校的信息进行关联。

接口的概念:

继承有两种用途:

一:继承基类的方法,并且做出自己的改变或者扩展(解决代码重用,但是子类与基类出现强耦合)

二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能。(推举使用)

归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

接口继承:就是定义一个父类,其主要目的就是所有的子类,必须去实现父类的方法(与是否省代码,么有半毛钱关系),父类可以不去具体实现,具体的实现由子类自己去实现。

举个例子:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样。

抽象类: 从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法(这种解释有点像接口了)

  1. #一切皆文件
  2. import abc #利用abc模块实现抽象类
  3.  
  4. class All_file(metaclass=abc.ABCMeta):
  5. all_type='file'
  6. @abc.abstractmethod #定义抽象方法,无需实现功能
  7. def read(self):
  8. '子类必须定义读功能'
  9. pass
  10.  
  11. @abc.abstractmethod #定义抽象方法,无需实现功能
  12. def write(self):
  13. '子类必须定义写功能'
  14. pass
  15.  
  16. # class Txt(All_file):
  17. # pass
  18. #
  19. # t1=Txt() #报错,子类没有定义抽象方法
  20.  
  21. class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
  22. def read(self):
  23. print('文本数据的读取方法')
  24.  
  25. def write(self):
  26. print('文本数据的读取方法')
  27.  
  28. class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
  29. def read(self):
  30. print('硬盘数据的读取方法')
  31.  
  32. def write(self):
  33. print('硬盘数据的读取方法')
  34.  
  35. class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
  36. def read(self):
  37. print('进程数据的读取方法')
  38.  
  39. def write(self):
  40. print('进程数据的读取方法')
  41.  
  42. wenbenwenjian=Txt()
  43.  
  44. yingpanwenjian=Sata()
  45.  
  46. jinchengwenjian=Process()
  47.  
  48. #这样大家都是被归一化了,也就是一切皆文件的思想
  49. wenbenwenjian.read()
  50. yingpanwenjian.write()
  51. jinchengwenjian.read()
  52.  
  53. print(wenbenwenjian.all_type)
  54. print(yingpanwenjian.all_type)
  55. print(jinchengwenjian.all_type)

继承实现的原理:(多继承,很多语言只支持单继承)

Python继承中有两种方式:一种是深度优先;另一种是广度优先;

当类是经典类时,多继承会按照深度优先方式查找;当类是新式类时,多继承会按照广度优先方式查找。注:当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

现在举个例子进行说明:

  1. class A(object):
  2. def test(self):
  3. print('from A')
  4.  
  5. class B(A):
  6. def test(self):
  7. print('from B')
  8.  
  9. class C(A):
  10. def test(self):
  11. print('from C')
  12.  
  13. class D(B):
  14. def test(self):
  15. print('from D')
  16.  
  17. class E(C):
  18. def test(self):
  19. print('from E')
  20.  
  21. class F(D,E):
  22. # def test(self):
  23. # print('from F')
  24. pass
  25. f1=F()
  26. f1.test()
  27. print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
  28.  
  29. #新式类继承顺序:F->D->B->E->C->A
  30. #经典类继承顺序:F->D->B->A->E->C
  31. #python3中统一都是新式类
  32. #pyhon2中才分新式类与经典类

在查找的过长中一旦找到查找过程就会立即中断,不会继续查找。

多继承的原理:(Python实现多继承的原理)

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如:

  1. F.mro() #等同于F.__mro__
  2. [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'objec
    t'>]

子类调用父类方法的实现过程:子类继承了父类的方法,然后想进行修改,注意了是基于原有的基础上修改,那么就需要在子类中调用父类的方法。

方法一:父类名.父类方法()

  1. class Vehicle: #定义交通工具类
  2. Country='China'
  3. def __init__(self,name,speed,load,power):
  4. self.name=name
  5. self.speed=speed
  6. self.load=load
  7. self.power=power
  8.  
  9. def run(self):
  10. print('开动啦...')
  11.  
  12. class Subway(Vehicle): #地铁
  13. def __init__(self,name,speed,load,power,line):
  14. Vehicle.__init__(self,name,speed,load,power) #子类继承父类
  15. self.line=line
  16.  
  17. def run(self):
  18. print('地铁%s号线欢迎您' %self.line)
  19. Vehicle.run(self)
  20.  
  21. line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
  22. line13.run()
  23.  
  24. # 地铁13号线欢迎您
  25. 开动啦...

方法二:super()(推举使用此种方式)

  1. class Vehicle: #定义交通工具类
  2. Country='China'
  3. def __init__(self,name,speed,load,power):
  4. self.name=name
  5. self.speed=speed
  6. self.load=load
  7. self.power=power
  8.  
  9. def run(self):
  10. print('开动啦...')
  11.  
  12. class Subway(Vehicle): #地铁
  13. def __init__(self,name,speed,load,power,line):
  14. #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
  15. super().__init__(name,speed,load,power)
  16. self.line=line
  17.  
  18. def run(self):
  19. print('地铁%s号线欢迎您' %self.line)
  20. super(Subway,self).run()
  21.  
  22. class Mobike(Vehicle):#摩拜单车
  23. pass
  24.  
  25. line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
  26. line13.run()

注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表。

    2.多态(性)

多态是指一个事物有多中形态(一个抽象类有多个子类,so 多态的概念依赖于继承),而多态性是指:指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。

在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

多态是反映在执行时的状态,在面向对象中,多态是怎么来得呢?首先,先定义一个基类,再定义一堆子类。其次,才能展现不同的类实例化出的实例去调用同一个方法。

  1. class H2O:
  2. def __init__(self,name,temperature):
  3. self.name=name
  4. self.temperature=temperature
  5. def turn_ice(self):
  6. if self.temperature < 0:
  7. print('[%s]温度太低结冰了' %self.name)
  8. elif self.temperature > 0 and self.temperature < 100:
  9. print('[%s]液化成水' %self.name)
  10. elif self.temperature > 100:
  11. print('[%s]温度太高变成了水蒸气' %self.name)
  12. def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(self):
  13. pass
  14.  
  15. class Water(H2O):
  16. pass
  17. class Ice(H2O):
  18. pass
  19. class Steam(H2O):
  20. pass
  21.  
  22. w1=Water('水',25)
  23. i1=Ice('冰',-20)
  24. s1=Steam('蒸汽',3000)
  25.  
  26. w1.turn_ice()
  27. i1.turn_ice()
  28. s1.turn_ice()

3.封装

装就是把东西包起来,而封的意思就是把口子封起来。为何要在编程的过程中使用这一特性呢?封装数据的作用就是为了保护隐私,而封装方法的作用就是为了隔离复杂程度。
    封装其实是有两个层面的意思:

其一:第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装。(注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口

其二:第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。

在Python中,用双下划线来实现隐藏属性(设置成私有的),(类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式)

  1. class A:
  2. __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
  3. def __init__(self):
  4. self.__X=10 #变形为self._A__X
  5. def __foo(self): #变形为_A__foo
  6. print('from A')
  7. def bar(self):
  8. self.__foo() #只有在类内部才可以通过__foo的形式访问到.
  9.  
  10. f1 = A()
  11. # f1.__foo() # 'A' object has no attribute '__foo'
  12. f1.bar() # 通过在对象A中创建一个接口,在内部调用私有方法

好了,今天就搞到这里,明天继续!!!

Python 基础 面向对象之二 三大特性的更多相关文章

  1. python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)

    python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...

  2. python基础——面向对象的程序设计

    python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...

  3. python基础——面向对象编程

    python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...

  4. python基础——面向对象进阶下

    python基础--面向对象进阶下 1 __setitem__,__getitem,__delitem__ 把对象操作属性模拟成字典的格式 想对比__getattr__(), __setattr__( ...

  5. python基础——面向对象进阶

    python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...

  6. python基础篇(二)

    PYTHON基础篇(二) if:else,缩进 A:if的基础格式和缩进 B:循环判断 C:range()函数和len()函数 D:break,contiue和pass语句 for,while循环 函 ...

  7. java基础(三)-----java的三大特性之多态

    面向对象编程有三大特性:封装.继承.多态. 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据.对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法. 继承 ...

  8. java基础(一)-----java的三大特性之封装

    面向对象编程有三大特性:封装.继承.多态.本文将介绍java的三大特性之封装 封装 封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成 ...

  9. python基础扩展(二)

    python基础扩展(二) 常用操作 1.startswith(以什么开始) endswith(y)什么结束 s='taiWanw39dd' print(s.startswith('t')) #意思是 ...

随机推荐

  1. Tensorflow-gpu在windows10上的安装(anaconda)

    文档来源转载: http://blog.csdn.net/u010099080/article/details/53418159 http://blog.nitishmutha.com/tensorf ...

  2. Java学习笔记之基础语法(数据类型)

    8种基本数据类型    整型:   byte[1字节]          short[2字节]        int[4字节]         long[8字节]      1,四种整型之间的区别:申 ...

  3. 渗透测试-基于白名单执行payload--Compiler

    复现亮神课程 0x01 Compiler前言 说明:Microsoft.Workflow.Comiler.exe是.NET Framework默认自带的一个实用工具,用户能够以XOML工作流文件的形式 ...

  4. postman-windows下newman的使用

    一.newman的安装 1.安装node.js下载https://nodejs.org/en/ C:\Users\iphauser>node -vv10.16.1C:\Users\iphause ...

  5. 百万年薪python之路 -- 带颜色的print

    带颜色的print print输出带颜色的方法详解 书写格式: 开头部分:\033[显示方式;前景色;背景色m + 结尾部分:\033[0m ​ 注意:开头部分的三个参数:显示方式,前景色,背景色是可 ...

  6. 百万年薪python之路 -- 小数据池和代码块

    1.小数据池和代码块 # 小数据池 -- 缓存机制(驻留机制) # == 判断两边内容是否相等 # a = 10 # b = 10 # print(a == b) # is 是 # a = 10 # ...

  7. The usage of Markdown---列表

    目录 1. 序言 2. 有序列表 3. 多级有序列表 3. 无序列表 4. 多级无序列表 5. 列表中的转义字符 6. 无效化 7. 任务列表 更新时间:2019.09.14 1. 序言   其实我昨 ...

  8. web常用知识

    Html 1.打电话,发短信和发邮件 <a href="tel:0755-10086">打电话给:0755-10086</a> <a href=&qu ...

  9. 数据类型(二)---day04

    目录 上节课回顾 五 变量 (一)什么是变量 (二)变量的组成 (三)变量名的命名规范 (四)常量 (五)python变量内存管理 (六)变量的三种打印方式 六 数据类型 (一)数字类型 (二)字符串 ...

  10. fenby C语言 P6

    printf=格式输出函数; printf=("两个相加的数字是:%d,%d,他们的和是:%d\n",a,b,c); %d整数方式输出; \n=Enter; int a=1; fl ...