iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python黑魔法:元类
  • 179
分享到

Python黑魔法:元类

黑魔法Python 2023-01-31 01:01:59 179人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

python黑魔法:元类 术语“元编程”指的是程序具有编写或操纵其自身作为它们资料的潜力。Python支持称为元类的类的元编程。 元类是一个深奥的面向对象编程(OOP)概念,隐藏在几乎所有的Python代码之后。无论你是否意识到它的存在,你

python黑魔法:元类

术语“元编程”指的是程序具有编写或操纵其自身作为它们资料的潜力。Python支持称为元类的类的元编程。

元类是一个深奥的面向对象编程(OOP)概念,隐藏在几乎所有的Python代码之后。无论你是否意识到它的存在,你都一直在使用它们。大多数情况下,你并不需要了解它。而且大多数Python程序员也很少用到,但是某些情况下你就不得不考虑使用元类。

当你有需要时,Python提供了一种不是所有面向对象语言都支持的功能:你可以深入了解其内部并自定义元类。使用定制元类经常会存在争议,正如Python大咖,创作了Python之禅的蒂姆·彼得斯所言:

“元类比99%的用户所忧虑的东西具有更深的魔法。如果你犹豫考虑是否需要它们,那么实质上你不会需要它们(实际需要它们的人确信他们确实需要,并且不需要进行任何解释)。“ —— 蒂姆·彼得斯

众多Pythonistas(即Python发烧友所熟知的Python大咖)认为你永远不应该使用自定义元类。这样说可能会有点极端,但大部分情况下自定义元类并不是必需的。如果一个问题不是很明显是否需要它们,那么如果以一种更简单的方式解决问题,代码可能会更干净,更具有可读性。

尽管如此,理解Python元类还是很有必要,因为它可以更好地理解Python类的内部实现。你永远不知道:你可能有一天会发现自己处于这样一种情况,即你确切明白自定义元类就是你想要的。

旧式类VS新式类

在Python范畴,一个类可以是两种类型之一。官方术语并没有对此进行确认,所以它们被非正式地称为旧式类和新式类。

旧式类

对于旧式类,类(class)和类型(type)并不完全相同。一个旧式类的实例总是继承自一个名为instance的内置类型。如果obj是旧式类的实例,那么obj.class就表示该类,但type(obj)始终是instance类型。以下示例来自Python 2.7:

新式类

新式类统一了类(class)和类型(type)的概念。如果obj是新式类的实例,type(obj)则与obj.class相同:

类型(Type)和类(Class)

在Python 3中,所有类都是新式类。因此,Python 3可以交换一个引用对象的类型和类。

注意:在Python 2中,默认所有类都是旧式类。在Python 2.2之前,根本不支持新式类。从Python 2.2开始,可以创建新式类,但必须明确声明它为新式类。

请记住,在Python中,一切都是对象。类也是对象。所以一个类(class)必须有一个类型(type)。那么类的类型是什么呢?

考虑下面的代码:

X的类型,正如你所想的,是类Foo,但Foo的类型,即类本身是type。一般来说,任何新式类的类型都是type。

您熟悉的内置类的类型也是type:

就此而言,type的类型也是type(是的,确实如此):

type是一个元类,任何类都是它的实例。就像一个普通的对象是一个类的实例一样,Python中的任何新式类以及Python 3中的任何类都是type元类的一个实例。

综上所述:

  • x是类Foo的一个实例。
  • Foo是type元类的一个实例。
  • type也是type元类的一个实例,所以它是它自己的一个实例。

动态定义类

内置type()函数在传递了一个参数时将返回一个对象的类型。对于新式类,通常与对象的class属性相同:

你也可以传递三个参数type(<name>, <bases>, <dct>)调用type():

  • <name>指定类名称,将成为该类的name属性。
  • <bases>指定继承类的基类元组,将成为该类的bases属性。
  • <dct>指定包含类主体定义的名称空间字典,将成为该类的dict属性。

以这种方式调用type()将创建一个type元类的新实例。换句话说,它动态地创建了一个新的类。

在下面每个示例中,前面的代码片段使用type()动态地定义了一个类,后面的代码片断使用常用的class语句定义了类。在每种情况下,这两个代码片段在功能上是一样的。

示例1

在第一个示例中,传递给type()的参数<bases>和<dct>都是空的,没有指定任何父类的继承,并且初始在命名空间字典中没有放置任何内容。这或许是最简单的类的定义:

示例2

这里,<bases>是一个具有单个元素Foo的元组,指定了Bar继承的父类。一个名为attr的属性最初放置在命名空间字典中:

示例3

这一次,<bases>又是空的。两个对象通过<dct>参数放置在命名空间字典中。第一个是属性attr,第二个是函数attr_val,该函数将成为已定义类的一个方法:

示例4

上面仅用Python中的lambda定义一个非常简单的函数。在下面的例子中,外部先定义了一个稍微复杂的函数f,然后在命名空间字典中通过函数名f分配给attr_val:

自定义元类

重新思考一下先前的这个例子:

表达式Foo()创建一个新的类Foo的实例。当解释器遇到Foo(),将按一下顺序进行解析:

  • 调用Foo父类的call()方法。由于Foo是标准的新式类,它的父类是type元类,所以type的call()方法被调用。
  • call()方法按以下顺序进行调用:
    • new()
    • init()

如果Foo没有定义new()和init(),那么将调用Foo父类的默认方法。但是如果Foo定义这些方法,就会覆盖来自父类的方法,这就允许在实例化Foo时可以自定义行为。

在下面的代码中,定义了一个自定义方法new(),并将它赋值给Foo的new()方法:

这会修改类Foo的实例化行为:每次Foo创建实例时,默认情况下都会将名为attr的属性进行初始化,将该属性设置为100。(类似于这样的代码通常会出现在init()方法中,不会出现在new()方法里,这个例子仅为演示目的而设计。)

现在,正如前面重申的那样,类也是对象。假设你想类似地在创建类Foo时自定义实例化行为。如果你要遵循上面的模式,则需要再次定义一个自定义方法,并将其指定为类Foo的实例的new()方法。Foo是type元类的一个实例,所以代码如下所示:

阿偶,你可以看到,不能重新指定元类type的new()方法。Python不允许这样做。

可以这么讲,type是派生所有新式类的元类。无论如何,你真的不应该去修改它。但是,如果你想自定义一个类的实例化,那么有什么办法呢?

一种可能的解决方案是自定义元类。本质上,不是去试图修改type元类,而是定义自己派生于type的元类,然后对其进行修改。

第一步是定义派生自type的元类,如下:

头部定义class Meta(type):指定了Meta派生自type。既然type是元类,那Meta也是一个元类。

请注意,重新自定义了Meta的new()方法。因为不可能直接对type元类进行此类操作。new()方法执行以下操作:

  • 经由super()指代的(type)元类的new()方法实际创建一个新的类
  • 将自定义属性attr分配给类,并设置值为100
  • 返回新创建的类

现在实现代码的另一半:定义一个新类Foo,并指定其元类为自定义元类Meta,而不是标准元类type。可以通过在类定义中使用关键字metaclass完成,如下所示:

瞧!Foo已经自动拥用了从Meta元类的属性attr。当然,你定义的任何其他类也会如此:

就像一个类作为创建对象的模板一样,一个元类可以作为创建类的模板。元类有时被称为类工厂。

比较以下两个示例:

对象工厂:

类工厂:

真的是必要的吗?

就像上面的类工厂的例子一样简单,它是metaclasses如何工作的本质。它们允许定制类的实例化。

尽管如此,仅仅为了赋予每个新创建的类的自定义属性attr,确实有点小题大做。你真的需要一个metaclass来实现吗?

在Python中,至少有其他一些方法可以实现同样的效果:

简单的继承:

类装饰器:

结论

正如蒂姆·彼得斯建议的,元类可以很容易地作为一种“寻找解决问题的方案”,通常不需要创建自定义元类。如果手头上的问题能够以更简单的方式解决,那或许就应该采用。尽管如此,了解元类有助于理解Python的类,并能够识别元类是否是工作中真正适合使用的工具

马哥IT高薪实战中心

Nginx服务12个常见技巧-马哥带你快速玩转Nginx,限时免费领取

【免费领取方式】↓

①、将下方生成带有自己专属头像的图片和心得分享到朋友圈或群

②、邀请【5】位好友扫码即可免费获得IT资料合集

③、邀请【10】位好友扫码即可加入IT技术大咖交流群

Nginx服务12个常见技巧资料包含:

1、Nginx基础配置和架构

2、企业应用配置12个技巧

3、企业级应用配置高级用法
Python黑魔法:元类

--结束END--

本文标题: Python黑魔法:元类

本文链接: https://www.lsjlt.com/news/183721.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python黑魔法:元类
    Python黑魔法:元类 术语“元编程”指的是程序具有编写或操纵其自身作为它们资料的潜力。Python支持称为元类的类的元编程。 元类是一个深奥的面向对象编程(OOP)概念,隐藏在几乎所有的Python代码之后。无论你是否意识到它的存在,你...
    99+
    2023-01-31
    黑魔法 Python
  • 定制类和黑魔法
    定制类  反射    反射又称为自省,指的是程序可以访问、检测和修改它本身状态和行为的一种能力。python中提供了以下四个自检功能的函数。    hasattr(object, name):用来检测object(适用于类、文件、模块或对...
    99+
    2023-01-30
    黑魔法
  • Python黑魔法之metaclass详情
    目录一、什么是 metaclass二、metaclass 能解决什么问题?三、通过一个实例来理解 metaclass四、Python 底层语言设计层面是如何实现 metaclass ...
    99+
    2024-04-02
  • Python 隐形大变身:PyInstaller 的黑魔法
    Python 凭借其广泛的库和易于使用的语法,已成为最受开发人员欢迎的编程语言之一。然而,当需要将 Python 应用程序部署为独立的可执行文件时,事情可能会变得复杂。这就是 PyInstaller 发挥作用的地方,它是 Python ...
    99+
    2024-02-15
    Python PyInstaller 打包 可执行文件 GUI
  • 改变 Python 对象规则的黑魔法 Metaclass
    今天小明哥要分享的主题是:改变类定义的神器-metaclass看到标题,你可能会想改变类的定义有什么用呢?什么时候才需要使用metaclass呢?今天我将带大家设计一个简单的orm框架,并简单剖析一下YAML这个序列化工具的原理。Pytho...
    99+
    2023-05-14
    Python Metaclass
  • python中类的魔术方法
    目的:学习python中class的magic methods,提高编程效率。环境:ubuntu 16.4   python 3.5.2在学习class时一定会接触到它的magic methods,比如常用__init__,形式都是前后有双...
    99+
    2023-01-31
    魔术 方法 python
  • Python黑魔法远程控制开机的实例
    目录 python黑魔法~只要知道你电脑的ip,远程控制便可开机,嘻嘻《只能用来学习哦~不可恶作剧哈》 def wake_up(request, mac='DC-4A-...
    99+
    2024-04-02
  • JavaScript 代理模式:破解黑魔法
    ...
    99+
    2024-04-02
  • 详解Python魔法方法之描述符类
    描述符类要求: 描述符就是将某种特殊类型的类的实例指派给另一个类的属性 至少要实现以下的一个方法: •__get__(self, instance, owner) ...
    99+
    2024-04-02
  • Python Tkinter 黑魔法:解锁 GUI 设计的无限可能
    Tkinter 是 Python 中用于创建图形用户界面 (GUI) 的一个跨平台库。它功能强大且易于使用,使开发人员能够快速创建美观且响应迅速的应用程序。 关键特性 跨平台兼容性: Tkinter 可以在多种操作系统上运行,包括 Wi...
    99+
    2024-04-02
  • Python黑魔法库安装及操作字典示例详解
    目录1. 安装方法2. 简单示例3. 兼容字典的所有操作4. 设置返回默认值5. 工厂函数自动创建key6. 序列化的支持7. 说说局限性本篇文章收录于《Python黑魔法手册》v3...
    99+
    2024-04-02
  • python类之特殊属性和魔术方法
    1 总述 属性 含义 _name_ 类,函数,方法等的名字 _module_ 类定义所现在的模块名 _class_ 对象或类所属的类 _bases_ 类的基类的元素,顺序为他们在基类列表中出现的顺序 _doc...
    99+
    2023-01-31
    魔术 属性 方法
  • python中的type,元类,类,对象用法
    目录type,元类,类,对象简单描述类的生成方式元类元类type学习总结type的作用是干什么呢?type,元类,类,对象 简单描述 1.type是python内建元类,新建的元类需...
    99+
    2024-04-02
  • Python魔法方法指南
    (译)Python魔法方法指南 原作者: Rafe Kettler翻译: hit9原版(英文版) Repo:https://github.com/RafeKettler/magicmethods 简介 本指南归纳于我的几个月的博客,主题...
    99+
    2023-01-31
    指南 方法 魔法
  • Python定制类你不知道的魔术方法
    目录Python中的魔法方法1.__str__2.__iter__3.__getitem__4.__getattr__5.__call__Python中的魔法方法 方法名说明__st...
    99+
    2024-04-02
  • Python魔法方法之描述符类的示例分析
    这篇文章给大家分享的是有关Python魔法方法之描述符类的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。描述符类要求:描述符就是将某种特殊类型的类的实例指派给另一个类的属性至少要实现以下的一个方法:•__...
    99+
    2023-06-15
  • 浅谈Python魔法方法
    特殊方法一览 在 Python 的学习和使用过程中, 你一定碰到过一些 特殊方法, 它们开头和结尾都有两条下划线, 也叫魔法方法 (Magic method), 或者 Dunder...
    99+
    2024-04-02
  • Python 魔法方法详解
    据说,Python 的对象天生拥有一些神奇的方法,它们总被双下划线所包围,他们是面向对象的 Python 的一切。 他们是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Py...
    99+
    2023-01-31
    详解 方法 魔法
  • python魔法方法之__setattr__()
    目录前言:1、实例属性管理__dict__2、__setattr__()与__dict__3、重载__setattr__()必须谨慎总结:前言: python提供了诸多的魔法方法,其...
    99+
    2024-04-02
  • Python中的魔法方法
    python中的魔法方法是一些可以让你对类添加“魔法”的特殊方法,它们经常是两个下划线包围来命名的。Python的魔法方法,也称为dunder(双下划线)方法。大多数的时候,我们将它们用于简单的事情,例如构造函数(init)、字符串表示(s...
    99+
    2023-05-14
    Python 运算符
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作