学习元类的时候,对__prepare__不是很理解,书上讲解的也不是很详细,最后通过查看stackoverflow的一些帖子对该方法有了一些理解,记录如下:

先看代码:

class member_table(dict):
def __init__(self):
self.member_names = [] def __setitem__(self, key, value):
if key not in self:
self.member_names.append(key) dict.__setitem__(self, key, value) class OrderedClass(type):
@classmethod
def __prepare__(metacls, name, bases):
classdict = member_table()
print("prepare return dict id is:", id(classdict))
return classdict def __new__(metacls, name, bases, classdict):
print("new get dict id is:", id(classdict))
result = type.__new__(metacls, name, bases, dict(classdict))
result.member_names = classdict.member_names
print("the class's __dict__ id is:", id(result.__dict__))
return result def __init__(cls, name, bases, classdict):
print("init get dict id is ", id(classdict))
super().__init__(name, bases, classdict) class MyClass(metaclass=OrderedClass):
def method1(self):
pass def method2(self):
pass print("MyClass locals() id is ", id(locals()))

输出为:

prepare return dict id is: 2093480992528
MyClass locals() id is 2093480992528
new get dict id is: 2093480992528
the class's __dict__ id is: 2093482830200
init get dict id is 2093480992528

可见,执行顺序为:

prepare(创建命名空间)-> 依次执行类定义语句 -> new(创建类)-> init(初始化类)

元类定义了prepare以后,会最先执行prepare方法,返回一个空的定制的字典,然后再执行类的语句,类中定义的各种属性被收集入定制的字典,最后传给new和init方法。

再来看其它输出:

MyClass.member_names
['__module__', '__qualname__', 'method1', 'method2']
MyClass.attr1 = 'attr1'
MyClass.__dict__
mappingproxy({'__dict__': <attribute '__dict__' of 'MyClass' objects>,
'__doc__': None,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'attr1': 'attr1',
'member_names': ['__module__',
'__qualname__',
'method1',
'method2'],
'method1': <function __main__.MyClass.method1>,
'method2': <function __main__.MyClass.method2>})
id(MyClass.__dict__)
2093482829864
MyClass.member_names
['__module__', '__qualname__', 'method1', 'method2']

上面的例子,在new方法中,dict被替换成一个普通的dict。所以MyClass.member_names不会记录class创建以后新增的属性。同时__dict__属性是类命名空间的一个代理,每次查看其id都不同。

3.6版本以前,prepare方法主要用来返回一个orderdict对象,以保存类中属性的添加顺序。而3.6版本以后,默认已经是保持顺序的了。

stackoverflow上的讨论帖

平时学习的一些笔记正在慢慢上传至github,欢迎大家交流。

地址是:https://github.com/telecomshy/python-study

Python元类__prepare__方法深入理解的更多相关文章

  1. Python进阶丨如何创建你的第一个Python元类?

    摘要:通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类. Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一. ...

  2. Python 元类 - Metaclasses

    Python 元类 - Metaclasses 默认情况下儿, classes 是有 type() 构造的. 类的结构体在一个新的 namespace 被执行, 类的名字 class name 绑定( ...

  3. Python元类实战,通过元类实现数据库ORM框架

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第19篇文章,我们一起来用元类实现一个简易的ORM数据库框架. 本文主要是受到了廖雪峰老师Python3入门教程的启 ...

  4. python元类:type和metaclass

    python元类:type和metaclass python中一切皆对象,所以类本身也是对象.类有创建对象的能力,那谁来创建类的呢?答案是type. 1.用tpye函数创建一个类 class A(ob ...

  5. Python元类之由浅入深

    前言 ​ 元类属于python面向对象编程的深层次的魔法,非常重要,它使我们可以更好的掌控类从创建到消亡的整个生命周期过程.很多框架的源码中都使用到了元类.例如 Django Framework 中的 ...

  6. python元类理解2

    恩,对元类理解又有新的收获,其实类似于装饰器,只不过装饰器是修饰函数,元类用来定制一个类. 代码如下,这是一个使用了函数做元类传递给类: input: def upper_attr(class_nam ...

  7. python元类深入理解

    1.python 中的类 在python中,类也是一个对象,只不过这个对象拥有生成实例的能力,我们一般使用class XXX来定义一个类,在python解释器执行到这个地方的时候会自动创建出这个对象, ...

  8. python 元类理解

    原文来自:https://segmentfault.com/a/1190000011447445 学懂元类,你只需要知道两句话: 道生一,一生二,二生三,三生万物 我是谁?我从哪来里?我要到哪里去? ...

  9. 深入理解python元类

    类也是对象 在理解元类之前,你需要先掌握Python中的类.Python 中的类概念借鉴 Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.当然在 P ...

随机推荐

  1. 通过class类获取类的成员变量和构造函数信息

  2. 674. Longest Continuous Increasing Subsequence最长连续递增子数组

    [抄题]: Given an unsorted array of integers, find the length of longest continuous increasing subseque ...

  3. oracle 创建表 外键约束

    create table usertable( id int primary key, username ) not null, birthday date, sex ), address ) ); ...

  4. Docker学习笔记_删除某个镜像

    实验:删除某个镜像 sudo docker rmi [Image ID] 1.查看镜像的ID                  sudo docker images 2.删除镜像            ...

  5. Python程序调试-TabError: inconsistent use of tabs and spaces in indentation

    报错信息:TabError: inconsistent use of tabs and spaces in indentation 说明:代码缩进统一使用Tab键或空格键,不能混用. 解决办法: 1. ...

  6. ssh时传递环境变量

    设置要传递的变量: -o SendEnv=Varname 但是不是每个都能传,受服务器上sshd_config里的下面两个选项的控制: AcceptEnv and PermitUserEnvironm ...

  7. Eclipse中新建applet 错误

    出现的问题:  “错误,请单击以获取详细信息” Java Plug-in 1.6.0_45 使用 JRE 版本 1.6.0_45-b06 Java HotSpot(TM) Client VM 用户主目 ...

  8. Java 设计模式 和七大设计原则

    创建型模式 抽象工厂模式(Abstract factory pattern): 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类. 生成器模式(Builder pattern): 使 ...

  9. 【leetcode】Move Zeroes

    Move Zeroes 题目: Given an array nums, write a function to move all 0‘s to the end of it while maintai ...

  10. 我用Django搭网站(1)-新浪微博登录

    新浪微博第三方登录使用的是OAuth2.0,开发前提已经注册开发者帐号,是开发者. OAuth简介 OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提 ...