Django源码中的metaclass使用是如何兼容Python2和Python3的

本文探讨了Django框架如何实现Python 2.x与3.x之间的元类兼容性,特别是聚焦于Django 2.0之前的版本。文章深入分析了Python 2.x与3.x中元类的不同使用方式,并通过具体代码示例展示了Django如何巧妙地利用six库中的with_metaclass函数解决这一难题。

之前看Django源码时没太注意metaclass是怎么做的2跟3的兼容,直到看见Django2.0dev版中只是用了Python3.x中metaclass的使用方式。

Django源码

某读者曰:喂喂,博主你上次写带那篇《如何阅读Django源代码-上篇(the5fire版) 》是不是太监了。。。

the5fire曰:不会的,下篇写到一半觉得没啥用,所以没继续写,啥时候有心情了会发出出来,让大家批评的。你瞧,这篇文章不也是个例证吗。阅读源码的几个入手点之一。

Django2.0开始不再兼容Python2.x了,因此Django2.0dev中的关于metaclass使用的代码是这样的:


点击查看源码

这是Python3.x中关于metaclass的使用,在Python2.x中,我们知道metaclass的使用是需要通过__metaclass__的定义来实现的,示例代码如下:

在Python2.x和Python3.x之间,关于metaclass的使用,已经是完全不兼容了,从语法层面。那么问题来了,Django2.0之前的版本是如何做到兼容的???

我们来看下Django1.11中这部分代码是怎么写的,github - django源码:

这个six.with_metaclass又是什么鬼呢?


嗯,看起来有点复杂,不过不要紧,接下来我们慢慢捋一捋。

先来理解__new__这个魔术方法

如果你实现过单例模式,那么你一定用过它了:


从这里我们能看到,__new__是用来创建实例(instance)的,我们在这可以控制创建出什么新的实例还是复用已有的实例。但是我们可以改下__new__的返回值。


这种情况下得到的是Foo这个类,而不是实例。因此我们可以通过在__new__这个方法里折腾点东西。

这里总结下,__new__是来控制类创建的,而__init__是来控制实例初始化的。

理解type

再来看type的使用,the5fire之前写的那篇《Django分表的两个方案》有说到怎么使用type动态创建类。可以通过这案例理解type的使用。而这里的type.new是类似的,我们在ipython中看下这俩函数的说明:

type(name, bases, dict) 返回一个新的类型,继承自传递进入的bases(这个参数必须是tuple类型),以及拥有dict参数中定义的属性。 type.__new__(S, ...) 返回一个S类型的新对象,注意,这个新对象并不是我们平时写代码中的类的实例,而是类。因为S必须是type的子类(继承自type)。

我们还是来通过代码认识下:

把上面代码放到本地,运行下试试。

其中[3]里面定义了CustomClass.__new__,你运行过上面代码后发现并没有print出来"in CustomClass"的结果。这意味着通过type.__new__创建的CustomClass的实例,并没有执行__new__这个方法。

我们继承下创建出来的这个Person试试:

为什么定义的时候就会输出"in CustomClass",也就是执行CustomClass.__new__呢,而不是像上面那样,在实例化的时候才执行?这就涉及到类创建的过程了,也就是metaclass的部分。我们稍后介绍,先来看关于type、类、实例的关系,可以从这个简略图理解下:


对应到上面第[3]部分的代码就是,我们通过type.__new__创建了CustomClass的实例(是一个类)Person,所以可以通过GoodPerson继承Person。

理解metaclass

理解了type之后,我们再来看metaclass的使用。我们以Python2.x的方式来解释。先看个示例代码:

你可以把这个代码copy到你电脑上的test_meta.py文件中,然后用Python2.7运行下。会得到如下输出:


也就是说,当类定义被执行的时候,就会开始执行metaclass中的方法了,这个方法的作用是创建类。那么问题又来了,大部分情况下我们并不会定义__metaclass__,那类是怎么创建的呢?还是甩文档出来:


这个__metaclass__你可以理解为Python暴露给我们的一个接口,用来自己实现创建类的过程。在这一过程中我们可以操作即将生成的类,比如上面的代码中,metacls.__new__里面的attrs['name'] = 'the5fire'这行代码,直接增加一个类级变量。当然也可以在这里增加方法的定义。

理解到这之后,再回过头来看我们上面的逻辑,我把完整代码copy到这:

我们解答上面的问题:


这是因为类的定义(或者说创建)的过程,是通过__metaclass__来完成的,虽然我们没有显示的定义__metaclass__,但是基于下面的规则,会把我们定义的class CustomClass作为metaclass,来创建类。

metaclass查找规则:如果当前类没有__metaclass__,但是有至少一个基类,那么会去使用第一个基类的__class__作为__metaclass__,如果没有__class__则会使用type来创建类。

上面的例子中,也就是GoodPerson没有查找到__metaclass__的定义,那么就会看是否存在Person.__class__,如果存在,就把它作为__metaclass__

对应的官网文档如下:

Python3的说明没找到,但是可以看源码:https://github.com/python/cpython/blob/master/Python/bltinmodule.c#L108 。其中的base0->ob_type可以理解为base.__class__也就是父类的类型。

再来看Django的six.with_meta代码

有了上面的认识,我们再来看Django中关于metaclass在Python2和Python3中兼容的处理就很好理解了。也就是除了在Python2中,通过:


或者Python3.x中通过:


的定义之外,还有另外的方法来指定metaclass,也就是上一节我们讲到的。

再来回顾下Django这部分代码,把代码合在一起:

这代码转换下就是:


看起来似乎没有问题,But,为啥需要两个metaclass: metaclassModelBase。是不是可以改成这样:


问题就是我注释地方支持的问题, 这种方式指定了metaclass之后,就无法设置子类了。

所以我们就能明白这段代码中,*bases参数,以及the5fire注释的那个位置的bases的作用了。

参考

- from the5fire.com  


文章转自:https://www.the5fire.com/





### Python Django 源码毕业设计示例及相关资源 在进行基于 Python Django 的毕业设计时,可以从多个角度出发寻找灵感参考资料。以下是几个常见的方向以及具体的项目实例: #### 1. 图书管理系统 图书管理系统是一个经典的 Django 应用案例,适合初学者理解实践 Django 的核心概念[^3]。该项目通常包括以下功能模块: - 用户注册与登录 - 图书分类管理 - 借阅记录跟踪 - 数据统计分析 可以通过 GitHub 上类似的开源项目获取代码结构技术实现思路。例如,GitHub 中有许多公开的图书管理系统源码可供参考。 #### 2. 博客平台 博客应用是另一个非常适合用于毕业设计的方向。它可以展示开发者对前端模板渲染、数据库模型定义以及用户交互的理解。主要功能可能包括: - 文章发布与编辑 - 分类标签支持 - 评论系统集成 - SEO 友好页面优化 下面是一段简单的文章模型定义代码片段: ```python from django.db import models class Article(models.Model): title = models.CharField(max_length=200, verbose_name="标题") content = models.TextField(verbose_name="正文") created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") class Meta: ordering = ['-created_at'] def __str__(self): return self.title ``` #### 3. 在线商城 在线购物网站能够综合运用 Django 提供的各种特性,如认证授权、支付接口对接等。基本需求如下: - 商品列表浏览 - 购物车操作逻辑 - 订单生成流程 - 支付网关接入(支付宝/微信) 对于此类复杂场景,建议先研究现成框架或第三方插件以减少重复劳动量[^4]。 #### 4. 社交网络服务(SNS) 构建小型社交平台有助于深入理解 RESTful API 设计原则及其实际应用场景。关键组件一般涉及: - 动态消息流更新机制 - 关注关系维护策略 - 私信聊天室搭建方案 --- ### 推荐的学习路径与工具链 为了顺利完成上述任一类型的毕业作品开发工作,还需要掌握必要的技能点并合理利用现有资源: - **官方文档**: 它是最权威也是最全面的信息来源之一,涵盖了从基础安装指导到高级主题讲解的所有方面[^1]。 - **社区论坛&问答站点**: 当遇到具体技术难题无法自行解决时,Stack Overflow 或 优快云 等平台上往往能找到相似问题的答案。 - **版本控制系统(Git)**: 使用 Git 对整个项目生命周期内的变更情况进行有效追踪非常重要[^2]。通过命令行完成初始化仓库(`git init`)、提交更改(`git commit`)直至推送至远程服务器的操作序列展示了这一过程的基本步骤。 最后提醒一点,在借鉴他人成果的同时务必注意版权归属问题,确保最终提交的作品完全符合学术诚信标准! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值