Python 中最黑魔法、最难懂的概念

简介: Python 中最黑魔法、最难懂的概念

大家好,我是老胡


最近在看一个开源框架的源码,其中大量使用了 metaclass 方法这个概念非常抽象,本文我就以一个有趣实用更简洁和通畅的方式来理解它。


元类 ( metaclass )应该是 Python 中最黑魔法、最难懂的概念之一,它提供了创造新类型的能力,为程序设计带来更多可能性。不少功能强大的开发框架,内部实现离不开 metaclass 的魔法。


Class


面向对象编程最重要的概念就是类(Class)和实例(Instance),我们先来创建一个 Lxs 的类,它有两个基本功 sing 和 dance ,lxs 是这个类的实例:


class Lxs(object): 
    def __init__(self, name, duration):
        self.name = name
        self.duration = duration
        print('%s practiced %s years' % (self.name, self.duration))
    def sing(self):
        print('%s good at singing' % self.name)
    def dance(self):
        print('%s good at dancing' % self.name)
lxs = Lxs('laohu',1.5)
lxs.sing()
lxs.dance()


练习时常1年半的老胡擅长唱和跳


恩,针不戳!


laohu practiced 1.5 years
laohu good at singing
laohu good at dancing


再来用__class__属性或type()看看 Lxs 和 lxs 分别是谁创建的


print(lxs.__class__)
print(Lxs.__class__)


lxs 是 Lxs 的实例,它创建自 Lxs ,这很容易理解。


我们 Lxs 类是 type 创建的?


<class '__main__.Lxs'>
<class 'type'>


一切对象都来自 type


先说结论:type 可以动态创建 类(class) ,对象是类(class)的实例,类(class)也是对象,是 type 的实例。type 为对象的顶点,所有对象都创建自 type 。


640.png


当使用 type 创建 class 时,其用法如下:


class = type(classname, superclasses, attributedict)
'''
classname:类名
superclasses:类的继承关系,用元组表示
attributedict:表示各种属性、方法,用字典表示
'''


继续上例,先定义__init__,sing 和 dance ,然后用 type 可以创建和上面完全一样的类:


Lxs = type('Lxs', (object,), dict( __init__= __init__,sing=sing,dance=dance))
lxs = Lxs('laohu',1)
lxs.sing()
print(lxs.__class__)
print(Lxs.__class__)


这里不得不提一下__call__这个属性


此方法会在实例作为一个函数被“调用”时被调用


这里等号右边的type(classname, superclasses, attributedict),就是 type 的

__call__运算符重载,它会进一步调用:


type.__new__(typeclass, classname, superclasses, attributedict)
type.__init__(class, classname, superclasses, attributedict)
# 这一部分我们以后有空再细品


总结一下:type 实际上是 Python 创建所有 class 的 metaclass。


metaclass


除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass。

先定义metaclass,就可以创建类,最后创建实例。


一句话:metaclass 是 type 的子类,是类的模板


metaclass 的主要目的是在 class 被创建的时候对生成的 class 进行自动的动态修改。

举个例子:像老胡就只会 sing 和 dance,有人还会rap,有人会说相声,我们定义很多的 class ,有一天,一个男人横空出世,他会打篮球!然后,所有的练习生也都学会了篮球,这可怎么修改?


metaclass 就可以施展魔法了


class LxsMetaclass(type):
    def __new__(cls, cls_name, bases, attrs):
        def basketball(self):
            print('%s good at basketball' % self.name)
        attrs['basketball'] = basketball
        return super(LxsMetaclass, cls).__new__(cls, cls_name, bases, attrs)


它指示Python解释器在创建 LxsMetaclass 时,要通过LxsMetaclass.new()来创建,在此,我们可以修改类的定义,比如,加上新的方法basketball(),然后,返回修改后的定义。


我们用 LxsMetaclass 这个模板创建类:


class Cxk(object, metaclass=LxsMetaclass):
    def __init__(self, name, duration):
        self.name = name
        self.duration = duration
        print('%s practiced %s years' % (self.name, self.duration))
    def sing(self):
        print('%s good at singing' % self.name)
    def dance(self):
        print('%s good at  dancing' % self.name)
    def rap(self):
        print('%s good at  rap' % self.name)
cxk = Cxk('cxk',2.5)
cxk.basketball()


运行结果如下,秀?


cxk practiced 2.5 years
cxk good at basketball



不过metaclass的作用肯定不限于此,举个例子,也算是个思考题,大家品一品。

比如 laohu 化身 xck 的粉丝,打着学篮球的幌子学 sing、dance和rap  :


class Funs(Cxk):
    def basketball(self):
        print('%s good at  singing&dancing&rap' % self.name)
fans = Funs('laohu',0.5)
fans.basketball()


运行结果会是什么呢?


laohu practiced 0.5 years
laohu good at basketball


laohu 真的就只学会了篮球。。。


这是为何呢?且听下回分解。

相关文章
|
6月前
|
存储 Python
Python文件编码概念详解
Python文件编码概念详解
60 1
|
3月前
|
存储 数据挖掘 数据库
探索Python编程:从基础到高级探索移动应用开发之旅:从概念到实现
【8月更文挑战第29天】本文将带你进入Python的世界,无论你是初学者还是有一定经验的开发者。我们将从Python的基础知识开始,然后逐步深入到更复杂的主题。你将学习到如何编写清晰、高效的代码,以及如何使用Python进行数据分析和网络编程。最后,我们将介绍一些高级主题,如装饰器和生成器。让我们一起开始这段旅程吧!
|
4月前
|
机器学习/深度学习 数据采集 数据可视化
Python数据分析入门涉及基础如Python语言、数据分析概念及优势。
【7月更文挑战第5天】Python数据分析入门涉及基础如Python语言、数据分析概念及优势。关键工具包括NumPy(数组操作)、Pandas(数据处理)、Matplotlib(绘图)、Seaborn(高级可视化)和Scikit-learn(机器学习)。流程涵盖数据获取、清洗、探索、建模、评估和展示。学习和实践这些将助你有效利用数据。
54 2
|
5月前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
61 0
|
2月前
|
测试技术 Python
探索Python中的装饰器:从基础概念到高级应用
本文深入探讨了Python中一个强大而灵活的特性——装饰器。从其基本定义出发,逐步解析装饰器的本质、运作机制以及如何高效利用这一工具来优化代码结构、增加功能和提升代码的可读性与可维护性。通过具体示例,包括自定义简单装饰器、带参数装饰器、多重装饰等高级话题,本文展示了装饰器在软件开发中的广泛应用,旨在为读者提供一个全面而实用的装饰器使用指南。
|
3月前
|
前端开发 JavaScript 数据可视化
Python+Dash快速web应用开发——基础概念篇
Python+Dash快速web应用开发——基础概念篇
|
3月前
|
Python
Python函数式编程:你真的懂了吗?理解核心概念,实践高阶技巧,这篇文章带你一次搞定!
【8月更文挑战第6天】本文介绍了Python中的函数式编程,探讨了高阶函数、纯函数、匿名函数、不可变数据结构及递归等核心概念。通过具体示例展示了如何利用`map()`和`filter()`等内置函数处理数据,解释了纯函数的一致性和可预测性特点,并演示了使用`lambda`创建简短函数的方法。此外,文章还强调了使用不可变数据结构的重要性,并通过递归函数实例说明了递归的基本原理。掌握这些技巧有助于编写更清晰、模块化的代码。
37 3
|
3月前
|
缓存 Python
探索Python中的装饰器:从概念到实战
【8月更文挑战第31天】装饰器,在Python中是一种强大的工具,能够让我们轻松地修改函数或类的行为。本文将带你从零开始理解装饰器的概念,并通过实际代码示例展示如何创建和使用它们。我们将一步步构建一个日志记录装饰器,并探讨其对提升代码可读性和重用性的影响。通过本文的学习,你将能够自信地在你的Python项目中应用装饰器技术。
|
4月前
|
网络协议 程序员 视频直播
|
4月前
|
Python
Python黑魔法揭秘:闭包与装饰器的高级玩法,让你代码飞起来
【7月更文挑战第7天】Python的闭包和装饰器是提升代码效率的神器。闭包是能记住外部作用域变量的内部函数,常用于动态函数创建。示例中,`make_multiplier_of`返回一个保留`n`值的闭包。装饰器则是一个接收函数并返回新函数的函数,用于在不修改原函数情况下添加功能,如日志或性能追踪。`@my_decorator`装饰的`say_hello`函数在执行时会自动加上额外操作。掌握这两者,能让Python代码更优雅、强大。**
34 1