python类的继承原理

一、类的继承顺序

class A(object):
def test(self):
print('from A')
pass
class B(A):
# def test(self):
# print('from B')
pass
class C(A):
# def test(self):
# print('from C')
pass
class D(A):
# def test(self):
# print('from D')
pass
class E(B):
# def test(self):
# print('from E')
pass
class F(C):
# def test(self):
# print('from F')
pass
class G(D):
# def test(self):
# print('from G')
pass
class H(E,F,G):
# def test(self):
# print('from H')
pass
h=H()
# h.test=1
# print h.__dict__
#新式类的在这中继承结构下,属性的查找关系
# h.test()

# H->E->B->F->C-G-D-A 广度优先
#mro
print(H.mro())

二、类的继承原理

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

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

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

三、子类调用父类的方法

两种方式 :一个是直接指明道姓的调用父类的函数属性还有一个是调用父类的__init__的功能,实际上用的是绑定方法。

class People:
# def __init__(self,name,age,sex):
# self.name=name
# self.age=age
# self.sex=sex
# def foo(self):
# print('from parent')
#
# class Teacher(People):
# def __init__(self,name,age,sex,salary,level):
# # People.__init__(self,name,age,sex) #指名道姓地调用People类的__init__函数
#
# #在python3中
# super().__init__(name,age,sex) #调用父类的__init__的功能,实际上用的是绑定方法
#
# #在python2中
# # super(Teacher,self).__init__(name,age,sex)
#
#
# self.salary=salary
# self.level=level
# def foo(self):
# super().foo()
# print('from child')
#
#
# t=Teacher('egon',18,'male',3000,10)
# # print(t.name,t.age,t.sex,t.salary,t.level)
# t.foo()

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

四封装

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

注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口

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

在python中用双下划线的方式实现隐藏属性(设置成私有的)

类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

 
#封装数据
#封装功能
class Teacher:
__school='oldboy' #_Teacher__school
def __init__(self,name,salary):
self.name=name
self.__salary=salary #self._Teacher__salary
 
def __foo(self):
print('====>')
t=Teacher('egon',3000)
 
# print(t.__school)
# print(Teacher.__dict__)
 
# t.foo()
# t._Teacher__foo()
 
# print(t.salary)
# print(t.__salary)
# print(t.__dict__)
#
# print(t._Teacher__salary)
 
#这种变形操作只在定义阶段发生
# Teacher.__N=111111
# print(Teacher.__dict__)
#
#
# t.__x=1
# print(t.__dict__)
 
#在类的外部,无法直接使用变形的属性,但是在类的内部可以直接使用
class Teacher:
__school='oldboy' #_Teacher__school='oldboy'
def __init__(self,name,salary):
self.name=name
self.__salary=salary #self._Teacher__salary=salary
 
def foo(self):
print('====>',self.__salary)
# print('====>',self._Teacher__salary)
t=Teacher('egon',3000)
 
print(t.__salary)
t.foo()

这种自动变形的特点:

1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果

2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

2.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

注意:对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了

五、类的特性(property

1 什么是特性property

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

2 为什么要用property

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

上代码:

class People:
def __init__(self,name,age,sex,height,weight,permission=False):
self.__name=name
self.__age=age
self.__sex=sex
self.__height=height
self.__weight=weight
self.permission=permission @property
def name(self):
return self.__name
@name.setter
def name(self,val):
if not isinstance(val,str):
raise TypeError('名字必须为字符串!')
self.__name=val
@name.deleter
def name(self):
if not self.permission:
raise PermissionError('权限不够!')
del self.__name
@property
def bmi(self):
return self.__weight/(self.__height**2)
def tell_info(self):
print('''
---------%s info------------
Name:%s
Age:%s
Sex:%s
Height:%sM
Weight:%sKG
---------------------------------
'''%(self.__name,self.__name,self.__age,self.__sex,self.__height,self.__weight))
niubin=People('niubin',20,'male',1.70,68)
niubin.tell_info()
print(niubin.name)
print(niubin.bmi)

Python进阶---面向对象第二弹的更多相关文章

  1. [Python3] 022 面向对象 第二弹

    目录 6. 面向对象的三大特性 6.1 封装 6.1.1 私有 private 6.1.2 受保护 protected 6.1.3 公开 public 6.2 继承 6.2.1 继承的概念与作用 6. ...

  2. Python进阶---面向对象的程序设计思想

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

  3. [Markdown] 04 进阶语法 第二弹

    [TOC] 接上一篇 [Mardkown] 03 进阶语法 第一弹 8. LaTeX 8.1 相关介绍 TeX:学术排版 LaTeX:相当于 TeX 的简化版本:对公式编辑精细至像素级别 MathJa ...

  4. Python进阶---面向对象第三弹(进阶篇)

    Python对象中一些方法 一.__str__ class Teacher: def __init__(self,name,age): self.name=name self.age=age self ...

  5. Python进阶【第二篇】多线程、消息队列queue

    1.Python多线程.多进程 目的提高并发 1.一个应用程序,可以有多进程和多线程 2.默认:单进程,单线程 3.单进程,多线程 IO操作,不占用CPU python的多线程:IO操作,多线程提供并 ...

  6. Python 进阶 - 面向对象

    Python 面向对象 面向过程 把完成某个需求的所有步骤,从头到尾逐步实现 根据开发需求,将某些功能独立的代码封装成一个又一个函数 最后完成的代码,就是顺序地调用不同的函数 面向过程特点: 注重步骤 ...

  7. Python进阶-面向对象

    类的成员 类的成员可以分为三类:字段.方法.属性 一:字段: 普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同 普通字段属于对象 静态字段属于类 字段的定义和使用 ...

  8. Python进阶(面向对象编程基础)(三)

    6.类属性和实例属性名字冲突怎么办 修改类属性会导致所有实例访问到的类属性全部都受影响,但是,如果在实例变量上修改类属性会发生什么问题呢? class Person(object): address ...

  9. Python进阶(面向对象编程基础)(二)

    1.初始化实例属性 #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'ziv·chan' #定义Person类的__init__方法 ...

随机推荐

  1. 轻量级文本编辑器,Notepad最佳替代品:Notepad++

    目录 正文之前 1. 目的 2. 原帖 3. 为何推荐Notepad++ 3.1. Notepad++的一些基本特点 3.2. notepad,notepad2,notepad++,ultraEdit ...

  2. OC实现同步访问属性

    有时候,我们在开发过程中需要对属性的访问进行同步操作,这种属性需要做成原子的,用atomic来修饰属性,即可实现这一点. 如果我们想自己实现,可以按照下面方式写代码: SFPerson.h #impo ...

  3. java多线程编程题之连续打印abc的几种解法

    一道编程题如下: 实例化三个线程,一个线程打印a,一个打印b,一个打印c,三个线程同时执行,要求打印出6个连着的abc 题目分析: 通过题意我们可以得出,本题需要我们使用三个线程,三个线程分别会打印6 ...

  4. Ubuntu 中登录相关的日志

    登录相关的日志涉及到系统的安全,所以是系统管理中非常重要的一部分内容.本文试图对登录相关的日志做一个整理. /var/log/auth.log 这是一个文本文件,记录了所有和用户认证相关的日志.无论是 ...

  5. C#基础之转换

    C#中一共有两种转换方式,隐式转换和显示转换 隐式转换:就是不需要声明就能进行的转换,通俗来说就是小范围内的数据类型转大范围数据类型 显示转换:就是通常说的强制转换,需要在代码中写明要的数据类型.通俗 ...

  6. win10 uwp MVVM入门

    MVVM 是一个强大的架构,基本从 WPF 开始,wr(我说的就是微软)就提倡使用 MVVM.它可以将界面和后台分离,让开发人员可以不关心界面是怎样,全心投入到后台代码编写中. 然后在编写完后台代码后 ...

  7. 聊聊Vue.js组件间通信的几种姿势

    写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出. 文章的原地址:https://github.com/a ...

  8. 上海2017QCon个人分享总结

    有幸作为讲师受邀参加InfoQ在上海举办的QCon2017,不得不说,不论是从讲师还是听众的角度衡量,QCon进一步扩大了技术视野.虽然前端专题只有四场,但每一场分享都是目前的热门话题.并且Qcon的 ...

  9. apache+php+mysql运行环境

    建议Apache2.4+php5.6+mysql5.5+phpmyadmin4.4.4 参考: http://jingyan.baidu.com/article/fcb5aff797ec41edaa4 ...

  10. LINUX 笔记-top命令

    top命令经常用来监控linux的系统状况,比如cpu.内存的使用. top - :: up day, :, users, load average: 0.00, 0.01, 0.00 Tasks: ...