Python 类与元类的深度挖掘 II【经验】

  上一篇解决了通过调用类对象生成实例对象过程中可能遇到的命名空间相关的一些问题,这次我们向上回溯一层,看看类对象本身是如何产生的。

  我们知道 type() 方法可以查看一个对象的类型,或者说判断这个对象是由那个类产生的:

  print(type(12))

  print(type('python'))

  class A:

  pass

  print(type(A))

  通过这段代码可以看出,类对象 A 是由type() 产生的,也就是说 type 也可以用来产生新的对象,而且产生的是类对象,因此它是所有类对象的类:

  print(type.__doc__)

  type(object_or_name, bases, dict)

  type(object) -> the object's type

  type(name, bases, dict) -> a new type

  class 定义类的语法实际上转化为 type(name, bases, dict),其中 name 参数为类的名字,bases 为继承父类的元组,dict 为类的属性和方法:

class A:
  pass
# 实际上等于
B = type('A', (), {})

print(A.__name__ == B.__name__)
True

  理论上说这就是元类的意义,但从实际的角度出发显然使用 class 语法更方便、合理,而元类的实际意义则是通过继承 type 类来构造一个新的元类,并进行特定的操作以产生具有特定行为的类对象。这样看来它的本质与普通的类对象没有差异,只不过继承的是 type 类。

  在生成实例时是通过调用 __init__ 方法进行初始化的,而实际上在此之前会先调用 __new__ 方法用于创建实例,再通过 __init__ 初始化,就好像 __new__ 负责声明变量,而 __init__ 负责对声明的变量进行初始化一样。这里有一个规则是 __new__(cls,) 的返回值必须是 cls 参数的实例,否则 __init__ 将不会触发,例如在 enum.Enum 的定义中,由于枚举类型是单例模式,因此在定义 __new__ 的时候没有返回其实例,也就不会进行初始化:

class Enum:

  def __new__(cls, value):

  print(cls, value)

  return value

  def __init__(self):

  print("Will not be called!")

  e = Enum(1)

   <class '__main__.Enum'> 1

  通常情况下自己定义 __new__ 需要通过调用父类的 __new__ 方法创建一个 cls 的实例,同样在定义元类的时候则是调用上面提到的 type 的用法(因为元类继承自 type):

  

class MetaEnum(type):

  def __new__(metaclass, name, base, attrs):

  print("Metaclass: {}\nName: {}\nParents: {}\nAttributes: {}".format(metaclass, name, base, attrs))

  return super().__new__(metaclass, name, base, attrs)

  class Enum(metaclass=MetaEnum):

  # Python 2.7 中定义元类的方法是使用 __metaclass__ 变量

  # [PEP 3115](https://www.python.org/dev/peps/pep-3115/)

  # 将 Python 3.0 以后语法改为 class Cls(metaclass=Meta)

  test = 0

  Metaclass: 

  Name: Enum

  Parents: ()

  Attributes: {'__qualname__': 'Enum', '__module__': '__main__', 'test': 0}

  此时我们再来看 Enum 的类,已经不再是 type 而是其元类 MetaEnum:

  type(Enum)

  __main__.MetaEnum

  除了 __new__ 方法之外,PEP 3115 还定义了 __prepare__ 属性,用于设定初始化的命名空间(即 type 的第 3 个参数),还是以 enum.Enum 为例,我们需要限制枚举类型中属性名称不得重复使用,则可以通过元类限制类的行为:

  # 定义新的字典类,在赋值新的 dict[k] = v 时

  # 检查 k 是否重复

 class _EnumDict(dict):

  def __init__(self):

  super().__init__()

  self.members = []

  def __setitem__(self, k, v):

  if k in self.members:

  raise TypeError("Attempted to reuse key: '{}'".format(k))

  else:

  self.members.append(k)

  super().__setitem__(k, v)

  class MetaEnum(type):

  @classmethod

  def __prepare__(metaclass, cls, bases):

  return _EnumDict()

  def __new__(metaclass, name, base, attrs):

  return super().__new__(metaclass, name, base, attrs)

  class Enum(metaclass=MetaEnum):

  pass

  class Color(Enum):

  try:

  red = 1

  red = 2

  except TypeError:# 这里没有使用 as err: 的原因是?

  print("TypeError catched")

  TypeError catched

  Python 中一切皆为对象,所有的对象都是某一类的实例,或是某一元类的实例,type 是自己的元类也是自己的实例

(0)

相关推荐

  • 深度剖析使用python抓取网页正文的源码

    本方法是基于文本密度的方法,最初的想法来源于哈工大的<基于行块分布函数的通用网页正文抽取算法>,本文基于此进行一些小修改. 约定:       本文基于网页的不同行来进行统计,因此,假设网页内容是没有经过压缩的,就是网页有正常的换行的. 有些新闻网页,可能新闻的文本内容比较短,但其中嵌入一个视频文件,因此,我会给予视频较高的权重:这同样适用于图片,这里有一个不足,应该是要根据图片显示的大小来决定权重的,但本文的方法未能实现这一点. 由于广告,导航这些非正文内容通常以超链接的方式出现,因此文本将

  • 13个最常用的Python深度学习库介绍

    如果你对深度学习和卷积神经网络感兴趣,但是并不知道从哪里开始,也不知道使用哪种库,那么这里就为你提供了许多帮助. 在这篇文章里,我详细解读了9个我最喜欢的Python深度学习库. 这个名单并不详尽,它只是我在计算机视觉的职业生涯中使用并在某个时间段发现特别有用的一个库的列表. 这其中的一些库我比别人用的多很多,尤其是Keras.mxnet和sklearn-theano. 其他的一些我是间接的使用,比如Theano和TensorFlow(库包括Keras.deepy和Blocks等). 另外的我只

  • python数据结构之图深度优先和广度优先实例详解

    本文实例讲述了python数据结构之图深度优先和广度优先用法.分享给大家供大家参考.具体如下: 首先有一个概念:回溯 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为"回溯点". 深度优先算法: (1)访问初始顶点v并标记顶点v已访问. (2)查找顶点v的第一个邻接顶点w. (3)若顶点v的邻接顶点w存在,则继续执行:否则回

  • Python 类与元类的深度挖掘 I【经验】

    上一篇介绍了 Python 枚举类型的标准库,除了考虑到其实用性,还有一个重要的原因是其实现过程是一个非常好的学习.理解 Python 类与元类的例子.因此接下来两篇就以此为例,深入挖掘 Python 中类与元类背后的机制. 翻开任何一本 Python 教程,你一定可以在某个位置看到下面这两句话: Python 中一切皆为对象(Everything in Python is an object); Python 是一种面向对象编程(Object Oriented Programming, OOP

  • 深度定制Python的Flask框架开发环境的一些技巧总结

    Flask 环境配置 你的应用程序可能需要大量的软件包才能正常的工作.如果都不需要 Flask 包的话,你有可能读错了教程.当应用程序运行的时候,你的应用程序的 环境 基本上是所有一切事情的根基.我们是幸运的,因为有许多方式使得我们能够轻松地管理我们的环境. 使用 virtualenv 管理你的环境 virtualenv是用于在所谓 虚拟环境 中隔离你的应用程序的一个工具.一个虚拟环境是包含了你的应用依赖的软件的一个目录.一个虚拟环境也能够改变你的环境变量以维持你的开发环境包含的环境变量.不用下

  • 深入理解Python中的元类(metaclass)

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也高达6

  • Python中的元类编程入门指引

    回顾面向对象编程 让我们先用 30 秒钟来回顾一下 OOP 到底是什么.在面向对象编程语言中,可以定义 类,它们的用途是将相关的数据和行为捆绑在一起.这些类可以继承其 父类的部分或全部性质,但也可以定义自己的属性(数据)或方法(行为).在定义类的过程结束时,类通常充当用来创建 实例(有时也简单地称为 对象)的模板.同一个类的不同实例通常有不同的数据,但"外表"都是一样 - 例如, Employee 对象 bob 和 jane 都有 .salary 和 .room_number ,但两者

  • 详解python metaclass(元类)

    元编程,一个听起来特别酷的词,强大的Lisp在这方面是好手,对于Python,尽管没有完善的元编程范式,一些天才的开发者还是创作了很多元编程的魔法.Django的ORM就是元编程的一个很好的例子. 本篇的概念和例子皆在Python3.6环境下 一切都是对象 Python里一切都是对象(object),基本数据类型,如数字,字串,函数都是对象.对象可以由类(class)进行创建.既然一切都是对象,那么类是对象吗? 是的,类也是对象,那么又是谁创造了类呢?答案也很简单,也是类,一个能创作类的类,就像

  • Python基础之元类详解

    1.python 中一切皆是对象,类本身也是一个对象,当使用关键字 class 的时候,python 解释器在加载 class 的时候会创建一个对象(这里的对象指的是类而非类的实例) class Student: pass s = Student() print(type(s)) # <class '__main__.Student'> print(type(Student)) # <class 'type'> 2.什么是元类 元类是类的类,是类的模板 元类是用来控制如何创建类的,

  •  python中的元类metaclass详情

    目录 动机 从一个问题引出 MetaClass Metaclass 编程 动机 python语言因为工作偏向于 AI ,所以对于这门语言还停留在表面,对于 python 深层并没有接触到. 今天来聊一聊元类(metaclass) ,想必大多数人都或多或少听过元编程这个词,但是对于元编程是什么以及如何应用元编程熟悉应该不多,在 python 中的 metaclass 就是帮助 developer 实现元编程,因此产生一个想法 最近时间还算宽裕,所以想要文章认真弄一弄 从一个问题引出 MetaCla

  • Python深入浅出分析元类

    目录 一.类和对象 二.type类 三.元类Metaclass 四.自定义一个元类 一.类和对象 Python属于动态类型的语言,而动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时创建的,而是运行时动态创建的,比方说我们要定义一个 Person 的class,就写一个 Person.py 模块: # -*- coding: utf-8 -*- # 文件名 : Person.py class Person(object): def say(self, s='元类'): print('今

  • 举例讲解Python中metaclass元类的创建与使用

    元类是可以让你定义某些类是如何被创建的.从根本上说,赋予你如何创建类的控制权. 元类也是一个类,是一个type类.   元类一般用于创建类.在执行类定义时,解释器必须要知道这个类的正确的元类,如果此属性没有定义,它会向上查找父类中的__metaclass__属性.如果还没发现,就查找全局变量.   对于传统类来说,它们的元类是types.ClassType.   元类也有构造器,传递三个参数:类名,从基类继承数据的元组,和类属性字典. 下面我们来定义一个元类,要求写类的时候必须给类提供一个__s

  • iOS中的类、元类以及isa示例详解

    前言 对于类相信大家都知道是什么,如果看过runtime的源码或者看过相关的文章对isa肯定也不陌生,不过元类(meta class)大家可能就比较陌生了.不过大家也不要担心,我会细细道来,让大家明白它到底是个什么东西. 先看一段大家非常熟悉的代码: Person *person = [[Person alloc] init]; 为什么Person类名就能调用到alloc方法吗?到底怎么找到了alloc的方法了呢? 1.首先,在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现

  • Python 类与元类的深度挖掘 II【经验】

    上一篇解决了通过调用类对象生成实例对象过程中可能遇到的命名空间相关的一些问题,这次我们向上回溯一层,看看类对象本身是如何产生的. 我们知道 type() 方法可以查看一个对象的类型,或者说判断这个对象是由那个类产生的: print(type(12)) print(type('python')) class A: pass print(type(A)) 通过这段代码可以看出,类对象 A 是由type() 产生的,也就是说 type 也可以用来产生新的对象,而且产生的是类对象,因此它是所有类对象的类

随机推荐