抽象基类: 继承的约束与协议

  1. __doc__ = """
  2. 抽象基类: 继承的约束与协议
  3. # 抽象基类 --- 有点java的味道,也有点golang的味道,继承,协议,接口
  4. 1.抽象基类不能实例化
  5. 2.必要时可以要求子类实现基类指定的抽象方法
  6. # 抽象基类的目的:
  7. 1.处理继承问题方面更加规范、系统
  8. 2.明确调用之间的相互关系
  9. 3.使得继承层次更加清晰
  10. 4.限定子类实现的方法
  11. # 参考
  12. https://www.osgeo.cn/cpython/library/abc.html # 介绍
  13. https://www.python.org/dev/peps/pep-3119/ # 缘由
  14. https://www.cnblogs.com/traditional/p/11731676.html # 使用
  15. """
  16. import abc
  17. class Base(abc.ABC):
  18. @abc.abstractmethod # 要求子类实现指定协议,抽象方法用@abstractmethod装饰器标记,而且定义体中通常只有文档字符串.
  19. def my_protocol(self):
  20. """要求子类实现的自定义协议"""
  21. def not_protocol(self):
  22. """不要求子类实现的自定义协议"""
  23. @classmethod
  24. def __subclasshook__(cls, subclass): # 同时作用于isinstance和issubclass
  25. """
  26. 此方法应返回 True , False 或 NotImplemented .
  27. 如果它回来 True , the 子类 被认为是ABC的一个子类。
  28. 如果它回来 False , the 子类 不被认为是ABC的一个子类,即使它通常是ABC的一个子类。
  29. 如果它回来 NotImplemented ,子类检查继续使用常规机制。
  30. """
  31. # print("subclass.__mro__:", subclass.__mro__) # 继承树
  32. if cls is Base:
  33. if any("my_protocol" in B.__dict__ for B in subclass.__mro__):
  34. return True
  35. else:
  36. return False
  37. return NotImplemented
  38. # 显式继承Base
  39. class MyClass(Base):
  40. """子类"""
  41. def my_protocol(self):
  42. pass
  43. # 显式继承Base
  44. class MyClass2(Base):
  45. """子类"""
  46. def my_protocol(self):
  47. pass
  48. @Base.register
  49. class MyClass3():
  50. """虚拟子类:issubclass和isinstance等函数都能识别,但是注册的类不会从抽象基类中继承任何方法或属性."""
  51. k = MyClass()
  52. print(isinstance(k, Base)) # True
  53. print(issubclass(MyClass, Base)) # True
  54. k2 = MyClass2()
  55. print(isinstance(k2, Base)) # True
  56. print(issubclass(MyClass2, Base)) # True
  57. k3 = MyClass3()
  58. print(isinstance(k3, Base)) # False
  59. print(issubclass(MyClass3, Base)) # False

元类: 用来拦截和修改 继承此元类 的子类的 创建

  1. __doc__ = """
  2. 元类: 用来拦截和修改 继承此元类 的子类的 创建
  3. # 为一个类定义确定适当的元类是根据以下规则:
  4. 1.如果没有基类且没有显式指定元类,则使用 type();
  5. 2.如果给出一个显式元类而且 不是 type() 的实例,则其会被直接用作元类;
  6. 3.如果给出一个 type() 的实例作为显式元类,或是定义了基类,则使用最近派生的元类。
  7. # 目的
  8. 了解元类的目的前需要先知道普通继承的作用与特点:
  9. 继承的特点:
  10. <1>减少代码量和灵活指定型类
  11. <2>子类具有父类的方法和属性
  12. <3>子类不能继承父类的私有方法或属性
  13. <4>子类可以添加新的方法
  14. <5>子类可以修改父类的方法
  15. 可以看到所有涉及到变动的特点都需要子类中实现,这样的话,对于某些固定模式的变动就需要子类中重复实现,增加子类中的代码量,
  16. 或者所有子类固定继承某一个中间类,并在中间类的__new__中根据子类模式去创建,元类就可以理解为python中单独提出来的中间类,
  17. 而一切类的创建最终都会调用type.__new__(cls, classname, bases, attrs)
  18. 元类的使用就是在子类创建时拦截并修改,可以依据子类的特点增加或修改属性.
  19. # 参考:
  20. https://docs.python.org/zh-cn/3/reference/datamodel.html#object.__new__
  21. https://docs.python.org/zh-cn/3/reference/datamodel.html#metaclasses
  22. """
  23. import abc
  24. from six import add_metaclass, with_metaclass # py2和py3的桥梁,元类相关的变化很大,可通过six做兼容.
  25. Meta = abc.ABCMeta
  26. # 通用做法。
  27. @add_metaclass(Meta)
  28. class MyClass(object):
  29. pass
  30. # 在Python 3 等价于
  31. class MyClass(object, metaclass=Meta):
  32. pass
  33. # 在Python 2.x (x >= 6)中等价于
  34. class MyClass(object):
  35. __metaclass__ = Meta
  36. pass
  37. # 或者直接调用装饰器,这里也能看出来装饰器就是个方法包装而已。
  38. class MyClass(object):
  39. pass
  40. MyClass = add_metaclass(Meta)(MyClass)
  41. # 再或者用 with_metaclass
  42. class MyClass(object, with_metaclass(Meta)):
  43. pass
  44. def with_metaclass(meta, *bases): # 代码摘自sqlalchemy中对元类的包装,采用了类似six.with_metaclass的方式
  45. """Create a base class with a metaclass.
  46. Drops the middle class upon creation.
  47. Source: http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/
  48. """
  49. class metaclass(meta):
  50. __call__ = type.__call__
  51. __init__ = type.__init__
  52. def __new__(cls, name, this_bases, d):
  53. if this_bases is None:
  54. return type.__new__(cls, name, (), d)
  55. return meta(name, bases, d)
  56. return metaclass("temporary_class", None, {})
  57. # 举例部分
  58. # 继承type 创建元类
  59. class SayMetaClass(type):
  60. # 用type动态生成类的的三个重要参数:类名称、父类、属性
  61. def __new__(cls, name, bases, attrs):
  62. # 创造"天赋"
  63. attrs['say_' + name] = lambda self, value, saying=name: print(saying + ',' + value + '!')
  64. # 类名称、父类、属性 生成元类
  65. return type.__new__(cls, name, bases, attrs)
  66. # 继承元类 创建类
  67. # class Hello(object, metaclass=SayMetaClass):
  68. class Hello(object, with_metaclass(SayMetaClass)):
  69. pass
  70. # 创建实列
  71. hello = Hello()
  72. # 调用实例方法
  73. hello.say_Hello('world!')
  74. # 普通类的创建与继承
  75. class Man:
  76. def __new__(cls, name, age): # 静态方法
  77. print('Man.__new__ called.', getattr(cls, 'work_copy')) # 能传过来
  78. return super(Man, cls).__new__(cls) # -->self
  79. # 对比普通类的继承与创建
  80. class Person(Man):
  81. """普通继承
  82. 对象是由 __new__() 和 __init__() 协作构造完成的 (由 __new__() 创建,并由 __init__() 定制),
  83. 所以 __init__() 返回的值只能是 None,否则会在运行时引发 TypeError。
  84. """
  85. def __new__(cls, name, age, work): # 可以不写,默认继承了Man.__new__
  86. print('Person.__new__ called.')
  87. cls.work_copy = work
  88. # return super(Person, cls).__new__(cls, name, age) # -->Man.__new__
  89. cls = super(Person, cls).__new__(cls, name, age) # 根据需要修改新创建的实例再将其返回
  90. cls.work = work # 可以看到,__new__也是可以做__init__的数值绑定的
  91. return cls
  92. def __init__(self, name, age, work): # 参数与__new__必须一致,__new__的后续构造
  93. print('Person.__init__ called.')
  94. self.name = name
  95. self.age = age
  96. # self.work = work
  97. def __str__(self):
  98. return '<Person: %s %s %s>' % (self.name, self.age, self.work)
  99. zhangsan = Person('zhangsan', 24, '张三')
  100. print(zhangsan)

Python抽象类以及元类的更多相关文章

  1. python基础——使用元类

    python基础——使用元类 type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello. ...

  2. Python基础:元类

    一.概述 二.经典阐述 三.核心总结 1.类的创建过程 2.元类的使用惯例 四.简单案例 1.默认行为 2.使用元类 五.实践为王 一.概述 Python虽然是多范式的编程语言,但它的数据模型却是 纯 ...

  3. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  4. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  5. 什么是python中的元类

    所属网站分类: python高级 > 面向对象 作者:goodbody 原文链接: http://www.pythonheidong.com/blog/article/11/ 来源:python ...

  6. Python之面向对象元类

    Python之面向对象元类 call方法: class People: def __init__(self,name): self.name=name # def __call__(self, *ar ...

  7. [Python之路] 元类(引申 单例模式)

    一.类也是对象 当我们定义一个变量或者函数的时候,我们可以在globals()的返回值字典中找到响应的映射: def A(): print("This is function A" ...

  8. Python 中的元类到底是什么?这篇恐怕是最清楚的了

    类作为对象 在理解元类之前,您需要掌握 Python 的类.Python 从 Smalltalk 语言中借用了一个非常特殊的类概念. 在大多数语言中,类只是描述如何产生对象的代码段.在 Python ...

  9. Python面向对象06 /元类type、反射、函数与类的区别、特殊的双下方法

    Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 目录 Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 1. 元类type 2. 反射 3 ...

随机推荐

  1. IOS真机测试(已拥有个人开发者证书)

    创建真机调试证书并进行真机测试 步骤1 在启动台中点击其他,找到钥匙串访问. 步骤2 在打开的界面中点击右边的系统根证书,然后点击左上角的钥匙串访问,然后是证书助理,最后点击从证书颁发机构申请证书. ...

  2. 【雕爷学编程】Arduino动手做(63)---TCS3200D颜色识别传感器

    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的.鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为 ...

  3. git push撤销、git commit 撤销、git add撤销、修改git提交信息

    原文地址:http://leisure.wang/?p=472 虽然自觉是一个Git工具的老手了,但是平时犯了一点错误,就发现有点捉襟见肘了.就好像今天我把一些代码玩坏了,想撤回到前几个版本去(此时已 ...

  4. PG修改参数方法

    1.查看参数文件位置 postgres=# show config_file; config_file ---------------------------------- /data/pgsql_d ...

  5. PL/SQL语言语法

    一.前言 SQL全称是"结构化查询语言(Structured Query Language)",而PL/SQL是过程语言(Procedure Language),是对SQL的扩展. ...

  6. SpringBoot_自动装配

    SpringBoot SrpingBoot 给人的第一印象就是 简洁,易上手.它是自 Spring 而来为了简化我们开发的,而经历过了 Spring 中繁琐的配置文件,我确实很好奇它到底是怎么帮我们把 ...

  7. CF922F Divisibility

    题目链接:http://codeforces.com/contest/922/problem/F 题目大意: 对于一个数集 \(I\),定义 \(f(I)\) 为 \(I\) 中满足条件的数对\((a ...

  8. 【MySQL】MySQL5.7等以上版本在Windows上的配置

    由于本人是win10系统,所以说下win10系统以管理员身份打开cmd 1. 配置环境变量 我这边是安装在了C:\Program Files\MySQL\MySQL Server 5.7在path中加 ...

  9. 17-4 delete-truncate语句-练习

    --删除数据语句: --delete from 表名 where ... --delete语句如果不加where条件,表示将表中所有的数据都删除,加where条件后,会按照where条件进行删除. - ...

  10. HTML5移动端最新兼容问题解决方案

    1.安卓浏览器看背景图片,有些设备会模糊.用同等比例的图片在PC机上很清楚,但是手机上很模糊,原因是什么呢?经过研究,是devicePixelRatio作怪,因为手机分辨率太小,如果按照分辨率来显示网 ...