一. 鸭子类型和多态

  1.什么是鸭子类型:

    在程序设计中,鸭子类型(英语:Duck typing)是动态类型和某些静态语言的一种对象推断风格。"鸭子类型"像多态一样工作,但是没有继承。“鸭子类型”的语言是这么推断的:一只鸟走起来像鸭子、游起泳来像鸭子、叫起来也像鸭子,那它就可以被当做鸭子。也就是说,它不关注对象的类型,而是关注对象具有的行为(方法)。

    可以看出,Cat,Dog,Duck中有相同的方法say(),当有一个函数调用Duck类时并调用say()方法,我们传入Cat类和Dog类也行,函数并不会检查对象是不是Duck,而是只要你有这样的方法就能运行。

  

如,列表的extend()方法只要参数是一个可迭代的对象就可以(list,set,tuple)

    还有前面的例子,只要实现了类中的__getitem__()魔法函数,就可以把类当作一个collection,实现啊__iter__和__next__就可以当作一个iterator。python中的鸭子类型允许我们使用任何提供所需方法的对象,而不需要迫使它成为一个子类。

  2.多态:

    由于python属于动态语言,当你定义了一个基类和基类中的方法,并编写几个继承该基类的子类时,由于python在定义变量时不指定变量的类型,而是由解释器根据变量内容推断变量类型的(也就是说变量的类型取决于所关联的对象),这就使得python的多态不像是c++或java中那样,定义一个基类类型变量而隐藏了具体子类的细节。

二. 抽象基类(abc模块)

  1.在某些情况下判断某个对象的类型:

    

  2.强制某个子类必须实现某些方法:

    

  3.模拟抽象基类:

    3.1利用内置抛错模拟:(但只有调用某些方法时才会抛异常)

      

 class CacheBase():
def get(self,key):
#默认抛出异常(Python内置错误)
raise NotImplementedError
def set(self,key,value):
raise NotImplementedError
#继承重写就不会抛异常
class Rediscatche(CacheBase):
def get(self,key):
pass
def set(self,key,value):
pass
cachebase=Rediscatche()
cachebase.set("key","value")

    3.2利用内置的abc模块:

    3.3通用的抽象基类(collections.abc模块,推荐使用多继承mixin,以防抽象基类设计过度):

      有可遍历,可哈希的等等抽象基类

        这些抽象基类都有一个魔法函数__subclasshook__():

      作用:Comp()没有继承Sized,但是却能判断出是Sized类型。

         __subclasshook__()会判断传入的C是否有“__len__”这个方法,有就返回为True

三. 使用isintance而不是type

   isinstance内部会去检查它的继承链,就可以判断它是A的类型,而type是指向B那个对象,判断是否和B是同一个对象。尽量应使用isinstance,而不是type,以免误判。

  

   is和==:

      is是判断两者是不是一个对象(即id是否相同),而==是判断值是否相同。如type(b)指向的是B这个对象,虽然B继承于A,但是A和B是两个不同的对象。

四. 类变量和对象变量

  注:1.魔法函数__init__中self是实例化对象,中的参数是对象变量,在实例化后调用变量是向上查找(即先查找对象变量,后查找类变量),类变量可以直接通过类访问;

    2.类变量是所有实例共享的

通过类修改类变量

通过实例对象修改变量

五. 类属性和实例属性以及查找顺序

  1.向上查找,即先查找对象变量(实例属性),后查找类属性:

  2.多继承采用MRO(【Method Resolution Order】:方法解析顺序)算法:

    Python语言包含了很多优秀的特性,其中多重继承就是其中之一,但是多重继承会引发很多问题,比如二义性,Python中一切皆引用,这使得他不会像C++一样使用虚基类处理基类对象重复的问题,但是如果父类存在同名函数的时候还是会产生二义性,Python中处理这种问题的方法就是MRO。

DFS:深度优先算法,这样查询顺序为A->B->D->C->E

这样就会出现问题(菱形继承):如果C继承D覆盖D中的某方法,在调用时是先查询D,然后查询C,则查询的方法是D中的,而不是C中重写的,因此在Python2

   后改成了广度优先的算法。

广度优先算法,这就解决了菱形继承,但是在第一种又出现了问题

如D和C中如果有个同名的方法,则会调用C中的方法,而不是D中的,而B是继承D的,因此从Python2.3后都统一为C3算法

  3.C3算法(参考:https://www.cnblogs.com/LLBFWH/p/10009064.html):  

    求某一类在多继承中的继承顺序:
    类的mro == [类] + [父类的继承顺序] + [父类2的继承顺序]
    如果从左到右的第一个类在后面的顺序中出现,那么就提取出来到mro顺序中
    [ABCD] + [EO] --> A = [BCD] + [EO]
    如果从左到右的第一个类在后面的顺序中出现,且在后面的顺序中也是第一位,那么就提出来到mro顺序中
    [ABCD] + [AEO] --> A = [BCD] + [EO]
    如果从左到右的第一个类在后面的顺序中出现,但不是在第一位,那么应该继续往后找,找到符合规则的项目
    [ABCD] + [EAO] --> E = [ABCD] + [AO]
    [ABCD] + [EAO] + [GEO] --> G = [ABCD] + [EAO] + [EO]
    [ABCD] + [EAO] + [EO] --> GE = [ABCD] + [AO] + [O]
    关键结论:
        这个类没有发生继承,他的顺序永远是[类o]
        只要是单继承,不是多继承,那么mro顺序就是从子类到父类的顺序

  4.查找顺序:

    4.1菱形继承:(Python2.3以前为经典类,默认不继承object(D),而2.3以后为新式类,默认继承object,即最后查找object类)

    

    4.2分别继承:

    

六. 静态方法、类方法以及对象方法

  1.实例方法:self为实例对象

  

  2.静态方法:(相当于普通的函数)

    (注:采用硬编码,如果类名改变,相应的静态方法中也要改变,如下面的Date改变,则parse_from_string中Date也相应改变)

    

利用外部对参数处理传入(每次都需要处理,麻烦)

 

利用静态方法

    静态方法用处:如在判断传入的参数是否为合法字符串,这是不用返回类对象,因此不用传入类(类方法)

      

  3.类方法:(传递的是类cls)

    注:相比静态方法,不是采用硬编码,无论类名称是什么,都不用修改类方法,且传递的是类(cls,只是名称,可以修改)

     

七. 数据封装和私有属性

  1.私有属性:

    

无法实例或类直接访问私有属性,只有通过类中的公共方法get_age间接访问

  2.私有属性原理:

    把具有双下划线的属性(如__birthday变为[_classname__attr]即_User__birthday),因此不是从语言层面解决了绝对私有性,只是加了一些小技巧。主要只是让我们书写更加规范,没有绝对的安全,也可以解决同样的变量名冲突的问题。如另一个类继承User,且也有__birthday,则根据规则是不一样的

    

仍然能访问

八. python对象的自省机制

  1.概念:

    自省是通过一定的机制查询到对象的内部结构

  2.__dict__,dir的使用:

    2.1通过dict查找属性:

   

实例的属性,但是通过name属性却能查找到(向上查找,name属性User类这个对象)

类属性,含有模板,文档,属性,弱引用等

     2.2通过__dict__添加修改属性:

      

    2.3通过dir查找属性(会列出所有属性,比__dict__更加详细): 

  

只有属性名称,没有属性值,还可以对list等使用

九. super函数

  

  1.如果想调用A中的构造函数:

      Python2:super(B,self).__init__()

          

      Python3中:super().__init__()

  2.既然重写A的构造函数,为什么还要调用super:

    很好的重用代码,如某个参数需要父类的构造函数处理,就可以调用super函数把参数交给父类的构造函数处理

    

将name交给Thread的构造函数处理

  3.super执行顺序: 

    super并不是直接调用父类,而是根据MRO算法的调用顺序(因此先是C,然后是A)

十. django rest framework中对多继承使用的经验

  1.建议:

    尽量不要使用多继承,以免造成混乱

  2.mixin多继承案例(如django restframework中的mixins):

    1.mixin类功能单一;

    2.不和基类关联,可以和任意基类组合,基类可以不和mixin关联就能初始化成功;

    3.在mixin中不要使用super函数;

    4.尽量以Mixin结尾

十一.python中的with语句

  1.try...except语句:

    except语句中将2压入堆栈中,finally又将4压入堆栈中,所以在取数据时直接从栈顶取数据,因此是4,如果没有finally则是前面的(如果要操作数据库,文件等,就需要在try中,except,finally中书写关闭连接,文件的逻辑)。

  2.上下文管理器:

    上下文管理器协议(需要实现两个魔法函数__enter__和__exit__):

      需要在__enter__中获取资源,在__exit__释放资源,只要满足这个协议就可以用with语句使用

       

                                  

十二. contextlib实现上下文管理器

    相当于简化__enter__和__exit__:@contextlib.contextmanager装饰器将__enter__和__exit__合起来并进行了一系列操作

十三.参考文献:

  MRO算法介绍

Python深入类和对象的更多相关文章

  1. 1.面向过程编程 2.面向对象编程 3.类和对象 4.python 创建类和对象 如何使用对象 5.属性的查找顺序 6.初始化函数 7.绑定方法 与非绑定方法

    1.面向过程编程 面向过程:一种编程思想在编写代码时 要时刻想着过程这个两个字过程指的是什么? 解决问题的步骤 流程,即第一步干什么 第二步干什么,其目的是将一个复杂的问题,拆分为若干的小的问题,按照 ...

  2. python的类和对象2(self参数)

    python的类和对象2(self参数) 1.python里面对象的方法都会有self参数,它就相当于C++里面的this指针:绑定方法,据说有了这个参数,Python 再也不会傻傻分不清是哪个对象在 ...

  3. Python初识类与对象

    Python初识类与对象 类与对象 世界观角度分析类与对象 类是一个抽象的概念,而对象是一个实体的存在,对象由类创造而出,每个对象之间互相独立互不影响,一个对象可以同时拥有多个类的方法,实例化就是通过 ...

  4. python的类与对象

    类与对象 1.什么是类 类和函数一样是程序编程的一种方式,在处理某些问题的时候类比函数更加适合让编程变得简化,在python里面函数式编程和类编程都是为了简化代码的一种编程方式,具体应用那个则由具体问 ...

  5. python的类和对象——番外篇(类的静态字段)

    什么是静态字段 在开始之前,先上图,解释一下什么是类的静态字段(我有的时候会叫它类的静态变量,总之说的都是它.后面大多数情况可能会简称为类变量.): 我们看上面的例子,这里的money就是静态字段,首 ...

  6. python的类和对象——进阶篇

    写在前面的话 终于,又到了周五.当小伙伴们都不再加班欢欢喜喜过周末的时候,我刚刚写完这一周的游戏作业,从面对晚归的紧皱眉头到现在的从容淡定,好像只有那么几周的时间.突然发现:改变——原来这么简单.很多 ...

  7. Python 定制类与其对象的创建和应用

    1.创建新类Athlete,创建两个唯一的对象实例sarah james,他们会继承Athlete类的特性 >>> class Athlete: def __init__(self, ...

  8. 【Python】类和对象、继承、使用文件、存储、异常、标准库(不懂)

    当你调用这个对象的方法MyObject.method(arg1, arg2)的时候,这会由Python自动转为MyClass.method(MyObject, arg1, arg2)——这就是self ...

  9. 搞懂Python的类和对象名称空间

    代码块的分类 python中分几种代码块类型,它们都有自己的作用域,或者说名称空间: 文件或模块整体是一个代码块,名称空间为全局范围 函数代码块,名称空间为函数自身范围,是本地作用域,在全局范围的内层 ...

随机推荐

  1. 006_Python 异常处理

    python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误.你可以使用该功能来调试python程序. 异常处理: 本站Python教程会具体介绍. 断言(Assertions) ...

  2. 微信硬件平台(八) 1 esp8266从自己的服务器获取token

    从txt获取token #include <ESP8266WiFi.h> #define host_token "www.dongvdong.top" #define ...

  3. 吴恩达课后作业学习1-week4-homework-two-hidden-layer -1

    参考:https://blog.csdn.net/u013733326/article/details/79767169 希望大家直接到上面的网址去查看代码,下面是本人的笔记 两层神经网络,和吴恩达课 ...

  4. JDK动态代理(1)-----------new 对象的方式

    //case 1: 直接newHelloWorldImpl helloWorldImpl = new HelloWorldImpl(); //case 2: 反射拿到类之后,通过newInstance ...

  5. java可重入锁reentrantlock

    public class ReentrantDemo { //重入锁 保护临界区资源count,确保多线程对count操作的安全性 /*public static ReentrantLock rtlo ...

  6. JavaScript模块化思想之CommonJS、AMD、CMD、UMD

    前一篇文章了解了什么是模块,这一篇就简单介绍一下如何定义并加载一个模块. 我所了解的三种模块加载方式分别是CommonJS.AMD和CMD 网上关于这三种模块加载方式讲解的文章很多,我就简单的做个介绍 ...

  7. TextField

    TextFiled 是一个输入Widget,属性如下: this.controller,//这个是传输数据用的this.focusNode,this.decoration = const InputD ...

  8. Windows下安装RabbitMQ报错:unable to perform an operation on node时的解决方案

    在计算机领域中,想要程序完成各种功能,那么数据的交流和计算是非常重要的.现在已知的程序动作机制有协程,线程和进程. 在同一个程序中,或者说同一个进程中,数据的交流,传递,计算是非常的简单,只要把相关数 ...

  9. 图解HTTP,TCP,IP,MAC的关系

    入门 用户发了一个HTTP的请求,想要访问我们网站的首页,这个HTTP请求被放在一个TCP报文中,再被放到一个IP数据报中,最终的目的地就是我们的115.39.19.22. 进阶 IP数据报其实是通过 ...

  10. Linux运维必会的MySQL企业面试题大全

    (1)基础笔试命令考察 1.开启MySQL服务 /etc/init.d/mysqld start service mysqld start systemctl start mysqld 2.检测端口是 ...