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

__doc__ = """
抽象基类: 继承的约束与协议 # 抽象基类 --- 有点java的味道,也有点golang的味道,继承,协议,接口
1.抽象基类不能实例化
2.必要时可以要求子类实现基类指定的抽象方法 # 抽象基类的目的:
1.处理继承问题方面更加规范、系统
2.明确调用之间的相互关系
3.使得继承层次更加清晰
4.限定子类实现的方法 # 参考
https://www.osgeo.cn/cpython/library/abc.html # 介绍
https://www.python.org/dev/peps/pep-3119/ # 缘由
https://www.cnblogs.com/traditional/p/11731676.html # 使用
""" import abc class Base(abc.ABC): @abc.abstractmethod # 要求子类实现指定协议,抽象方法用@abstractmethod装饰器标记,而且定义体中通常只有文档字符串.
def my_protocol(self):
"""要求子类实现的自定义协议""" def not_protocol(self):
"""不要求子类实现的自定义协议""" @classmethod
def __subclasshook__(cls, subclass): # 同时作用于isinstance和issubclass
"""
此方法应返回 True , False 或 NotImplemented .
如果它回来 True , the 子类 被认为是ABC的一个子类。
如果它回来 False , the 子类 不被认为是ABC的一个子类,即使它通常是ABC的一个子类。
如果它回来 NotImplemented ,子类检查继续使用常规机制。
"""
# print("subclass.__mro__:", subclass.__mro__) # 继承树 if cls is Base:
if any("my_protocol" in B.__dict__ for B in subclass.__mro__):
return True
else:
return False
return NotImplemented # 显式继承Base
class MyClass(Base):
"""子类""" def my_protocol(self):
pass # 显式继承Base
class MyClass2(Base):
"""子类""" def my_protocol(self):
pass @Base.register
class MyClass3():
"""虚拟子类:issubclass和isinstance等函数都能识别,但是注册的类不会从抽象基类中继承任何方法或属性.""" k = MyClass()
print(isinstance(k, Base)) # True
print(issubclass(MyClass, Base)) # True k2 = MyClass2()
print(isinstance(k2, Base)) # True
print(issubclass(MyClass2, Base)) # True k3 = MyClass3()
print(isinstance(k3, Base)) # False
print(issubclass(MyClass3, Base)) # False

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

__doc__ = """
元类: 用来拦截和修改 继承此元类 的子类的 创建 # 为一个类定义确定适当的元类是根据以下规则:
1.如果没有基类且没有显式指定元类,则使用 type();
2.如果给出一个显式元类而且 不是 type() 的实例,则其会被直接用作元类;
3.如果给出一个 type() 的实例作为显式元类,或是定义了基类,则使用最近派生的元类。 # 目的
了解元类的目的前需要先知道普通继承的作用与特点:
继承的特点:
<1>减少代码量和灵活指定型类
<2>子类具有父类的方法和属性
<3>子类不能继承父类的私有方法或属性
<4>子类可以添加新的方法
<5>子类可以修改父类的方法 可以看到所有涉及到变动的特点都需要子类中实现,这样的话,对于某些固定模式的变动就需要子类中重复实现,增加子类中的代码量,
或者所有子类固定继承某一个中间类,并在中间类的__new__中根据子类模式去创建,元类就可以理解为python中单独提出来的中间类,
而一切类的创建最终都会调用type.__new__(cls, classname, bases, attrs)
元类的使用就是在子类创建时拦截并修改,可以依据子类的特点增加或修改属性. # 参考:
https://docs.python.org/zh-cn/3/reference/datamodel.html#object.__new__
https://docs.python.org/zh-cn/3/reference/datamodel.html#metaclasses """ import abc
from six import add_metaclass, with_metaclass # py2和py3的桥梁,元类相关的变化很大,可通过six做兼容. Meta = abc.ABCMeta # 通用做法。
@add_metaclass(Meta)
class MyClass(object):
pass # 在Python 3 等价于
class MyClass(object, metaclass=Meta):
pass # 在Python 2.x (x >= 6)中等价于
class MyClass(object):
__metaclass__ = Meta
pass # 或者直接调用装饰器,这里也能看出来装饰器就是个方法包装而已。
class MyClass(object):
pass MyClass = add_metaclass(Meta)(MyClass) # 再或者用 with_metaclass
class MyClass(object, with_metaclass(Meta)):
pass def with_metaclass(meta, *bases): # 代码摘自sqlalchemy中对元类的包装,采用了类似six.with_metaclass的方式
"""Create a base class with a metaclass. Drops the middle class upon creation. Source: http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ """ class metaclass(meta):
__call__ = type.__call__
__init__ = type.__init__ def __new__(cls, name, this_bases, d):
if this_bases is None:
return type.__new__(cls, name, (), d)
return meta(name, bases, d) return metaclass("temporary_class", None, {}) # 举例部分 # 继承type 创建元类
class SayMetaClass(type):
# 用type动态生成类的的三个重要参数:类名称、父类、属性
def __new__(cls, name, bases, attrs):
# 创造"天赋"
attrs['say_' + name] = lambda self, value, saying=name: print(saying + ',' + value + '!')
# 类名称、父类、属性 生成元类
return type.__new__(cls, name, bases, attrs) # 继承元类 创建类
# class Hello(object, metaclass=SayMetaClass):
class Hello(object, with_metaclass(SayMetaClass)):
pass # 创建实列
hello = Hello()
# 调用实例方法
hello.say_Hello('world!') # 普通类的创建与继承
class Man:
def __new__(cls, name, age): # 静态方法
print('Man.__new__ called.', getattr(cls, 'work_copy')) # 能传过来
return super(Man, cls).__new__(cls) # -->self # 对比普通类的继承与创建 class Person(Man):
"""普通继承
对象是由 __new__() 和 __init__() 协作构造完成的 (由 __new__() 创建,并由 __init__() 定制),
所以 __init__() 返回的值只能是 None,否则会在运行时引发 TypeError。
""" def __new__(cls, name, age, work): # 可以不写,默认继承了Man.__new__
print('Person.__new__ called.')
cls.work_copy = work
# return super(Person, cls).__new__(cls, name, age) # -->Man.__new__
cls = super(Person, cls).__new__(cls, name, age) # 根据需要修改新创建的实例再将其返回
cls.work = work # 可以看到,__new__也是可以做__init__的数值绑定的
return cls def __init__(self, name, age, work): # 参数与__new__必须一致,__new__的后续构造
print('Person.__init__ called.')
self.name = name
self.age = age
# self.work = work def __str__(self):
return '<Person: %s %s %s>' % (self.name, self.age, self.work) zhangsan = Person('zhangsan', 24, '张三')
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. 轻松扩展机器学习能力:如何在Rancher上安装Kubeflow

    随着机器学习领域不断发展,对于处理机器学习的团队来说,在1台机器上训练1个模型已经有些难以为继,并且现在业界的共识是机器学习已经不仅仅是简单的模型训练. 在模型训练之前.过程中和之后,需要进行许多活动 ...

  2. 横向滚动div

    <div id="shelf"> <div class="books"><div> <div class=" ...

  3. Kubernetes学习笔记(二):Pod、标签、注解

    pod与容器 一个pod是一组紧密相关的容器,它们总是一起运行在同一个节点上,以及同一个LInux命名空间中. 每个pod拥有自己的ip,包含若干个容器.pod分布在不同的节点上. 为什么需要pod ...

  4. 3.1Go变量

    3.1 Go变量 变量是对内存中数据存储空间的表示,如同门牌号对应着房间,同样的,变量名字对应变量的值. 变量:本质就是一块内存空间.用于存储某个数值.该数值在运行时可以改变. 变量使用步骤 1.声明 ...

  5. 06 返回静态文件的映射(函数/多线程)web框架

    06 返回静态文件的映射(函数/多线程)web框架 服务器server端python程序(函数版): import socket server = socket.socket() server.bin ...

  6. spring源码解析-ApplicationContext解析

    ApplicationContext和BeanFactory一样都是bean的容器,而BeanFactory是一切Bean容器的父类,ApplicationContext继承于BeanFactory( ...

  7. 存储系列之 LUN 和 LVM

    一.LUN 1.LUN的由来 上一篇文章已经介绍了RAID技术的原理,那么RAID的实现呢?有两种方式,RAID软件和RAID硬件.但是因软件RAID占用主机CPU和主机内存,而且RAID功能不易实现 ...

  8. 本地项目链接github项目库

    本地有个用了好久用来测试功能的项目,今天用来测试链接github项目库,做一下记录   目标:把本地的项目和github上的项目连接起来 工具:sourceTree   sourceTree提供了gi ...

  9. 如何在npm发布轮子

    我们在前端工程开发中通常使用npm这个包管理器来安装各种好用的轮子(当然也有用yarn的),不安分的码工就想,也发布一个试试,哪怕只是一个小时候滚的铁环而不是轮子. 首先,要在 npmjs官网注册自己 ...

  10. KNIME快速入门指南

    一.介绍  KNIME Analytics Platform是用于创建数据科学应用程序和服务的开源软件.KNIME直观,开放,不断整合新的开发,使人们可以理解数据,设计数据科学工作流程和可重用组件. ...