为什么类定义的元类关键字参数接受可调用对象?

2023-12-31

背景

蟒蛇3文档 https://docs.python.org/3.6/reference/datamodel.html#determining-the-appropriate-metaclass清楚地描述了类的元类是如何确定的:

  • 如果没有给出基类和显式元类,则使用 type()
  • 如果给出了显式元类并且它不是 type() 的实例,则直接将其用作元类
  • 如果 type() 的实例作为显式元类给出,或者定义了基类,则使用最派生的元类

因此,根据第二条规则,可以使用可调用对象来指定元类。例如。,

class MyMetaclass(type):
    pass

def metaclass_callable(name, bases, namespace):
    print("Called with", name)
    return MyMetaclass(name, bases, namespace)

class MyClass(metaclass=metaclass_callable):
    pass

class MyDerived(MyClass):
    pass

print(type(MyClass), type(MyDerived))

问题1

是元类MyClass: metaclass_callable or MyMetaclass?文档中的第二条规则表示提供的可调用“直接用作元类”。然而,元类似乎更有意义MyMetaclass since

  • MyClass and MyDerived有类型MyMetaclass,
  • metaclass_callable被调用一次,然后似乎无法恢复,
  • 派生类不使用(据我所知)metaclass_callable以任何方式(他们使用MyMetaclass).

问题2

有没有什么事情是你可以用可调用函数做而不能用它的实例做的?type?接受任意可调用的目的是什么?


关于你的第一个问题,元类应该是MyMetaclass(事情是这样的):

In [7]: print(type(MyClass), type(MyDerived))
<class '__main__.MyMetaclass'> <class '__main__.MyMetaclass'>

原因是,如果元类不是类型的实例,python 通过将这些参数传递给它来调用元类name, bases, ns, **kwds (see new_class)并且由于您在该函数中返回真实的元类,因此它获得了元类的正确类型。

关于第二个问题:

接受任意可调用的目的是什么?

没有什么特别的目的,这实际上是元类的本质这是因为从类创建实例总是通过调用它来调用元类__call__ method:

Metaclass.__call__()

这意味着您可以将任何可调用对象作为元类传递。因此,例如,如果您使用嵌套函数测试它,结果仍然是相同的:

In [21]: def metaclass_callable(name, bases, namespace):
             def inner():
                 return MyMetaclass(name, bases, namespace)
             return inner()
   ....: 

In [22]: class MyClass(metaclass=metaclass_callable):
             pass
   ....: 

In [23]: print(type(MyClass), type(MyDerived))
<class '__main__.MyMetaclass'> <class '__main__.MyMetaclass'>

有关更多信息,请参阅 Python 如何创建类:

它称为new_class它调用的函数prepare_class在其内部,然后正如您在内部所看到的prepare_classpython 调用__prepare__适当的元类的方法,除了找到适当的元(使用_calculate_metafunction ) 并为类创建适当的命名空间。

因此,这里的全部内容就是执行元类方法的层次结构:

  1. __prepare__ 1
  2. __call__
  3. __new__
  4. __init__

这是源代码:

# Provide a PEP 3115 compliant mechanism for class creation
def new_class(name, bases=(), kwds=None, exec_body=None):
    """Create a class object dynamically using the appropriate metaclass."""
    meta, ns, kwds = prepare_class(name, bases, kwds)
    if exec_body is not None:
        exec_body(ns)
    return meta(name, bases, ns, **kwds)

def prepare_class(name, bases=(), kwds=None):
    """Call the __prepare__ method of the appropriate metaclass.

    Returns (metaclass, namespace, kwds) as a 3-tuple

    *metaclass* is the appropriate metaclass
    *namespace* is the prepared class namespace
    *kwds* is an updated copy of the passed in kwds argument with any
    'metaclass' entry removed. If no kwds argument is passed in, this will
    be an empty dict.
    """
    if kwds is None:
        kwds = {}
    else:
        kwds = dict(kwds) # Don't alter the provided mapping
    if 'metaclass' in kwds:
        meta = kwds.pop('metaclass')
    else:
        if bases:
            meta = type(bases[0])
        else:
            meta = type
    if isinstance(meta, type):
        # when meta is a type, we first determine the most-derived metaclass
        # instead of invoking the initial candidate directly
        meta = _calculate_meta(meta, bases)
    if hasattr(meta, '__prepare__'):
        ns = meta.__prepare__(name, bases, **kwds)
    else:
        ns = {}
    return meta, ns, kwds


def _calculate_meta(meta, bases):
    """Calculate the most derived metaclass."""
    winner = meta
    for base in bases:
        base_meta = type(base)
        if issubclass(winner, base_meta):
            continue
        if issubclass(base_meta, winner):
            winner = base_meta
            continue
        # else:
        raise TypeError("metaclass conflict: "
                        "the metaclass of a derived class "
                        "must be a (non-strict) subclass "
                        "of the metaclasses of all its bases")
    return winner

1. Note that it get called implicitly inside the new_class function and before the return.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么类定义的元类关键字参数接受可调用对象? 的相关文章

  • 将 Matplotlib 误差线放置在不位于条形中心的位置

    我正在 Matplotlib 中生成带有错误栏的堆积条形图 不幸的是 某些层相对较小且数据多样 因此多个层的错误条可能重叠 从而使它们难以或无法读取 Example 有没有办法设置每个误差条的位置 即沿 x 轴移动它 以便重叠的线显示在彼此
  • 如何在flask中使用g.user全局

    据我了解 Flask 中的 g 变量 它应该为我提供一个全局位置来存储数据 例如登录后保存当前用户 它是否正确 我希望我的导航在登录后在整个网站上显示我的用户名 我的观点包含 from Flask import g among other
  • 从字符串中删除识别的日期

    作为输入 我有几个包含不同格式日期的字符串 例如 彼得在16 45 我的生日是1990年7月8日 On 7 月 11 日星期六我会回家 I use dateutil parser parse识别字符串中的日期 在下一步中 我想从字符串中删除
  • 如何在 Python 中检索 for 循环中的剩余项目?

    我有一个简单的 for 循环迭代项目列表 在某些时候 我知道它会破裂 我该如何退回剩余的物品 for i in a b c d e f g try some func i except return remaining items if s
  • PyUSB 1.0:NotImplementedError:此平台不支持或未实现操作

    我刚刚开始使用 pyusb 基本上我正在玩示例代码here https github com walac pyusb blob master docs tutorial rst 我使用的是 Windows 7 64 位 并从以下地址下载 z
  • 根据列值突出显示数据框中的行?

    假设我有这样的数据框 col1 col2 col3 col4 0 A A 1 pass 2 1 A A 2 pass 4 2 A A 1 fail 4 3 A A 1 fail 5 4 A A 1 pass 3 5 A A 2 fail 2
  • 如何加速Python中的N维区间树?

    考虑以下问题 给定一组n间隔和一组m浮点数 对于每个浮点数 确定包含该浮点数的区间子集 这个问题已经通过构建一个解决区间树 https en wikipedia org wiki Interval tree 或称为范围树或线段树 已经针对一
  • AWS EMR Spark Python 日志记录

    我正在 AWS EMR 上运行一个非常简单的 Spark 作业 但似乎无法从我的脚本中获取任何日志输出 我尝试过打印到 stderr from pyspark import SparkContext import sys if name m
  • 添加不同形状的 numpy 数组

    我想添加两个不同形状的 numpy 数组 但不进行广播 而是将 缺失 值视为零 可能最简单的例子是 1 2 3 2 gt 3 2 3 or 1 2 3 2 1 gt 3 2 3 1 0 0 我事先不知道形状 我正在弄乱每个 np shape
  • Flask如何获取请求的HTTP_ORIGIN

    我想用我自己设置的 Access Control Allow Origin 标头做出响应 而弄清楚请求中的 HTTP ORIGIN 参数在哪里似乎很混乱 我在用着烧瓶 0 10 1 以及HTTP ORIGIN似乎是这个的特点之一object
  • 在Python中获取文件描述符的位置

    比如说 我有一个原始数字文件描述符 我需要根据它获取文件中的当前位置 import os psutil some code that works with file lp lib open path to file p psutil Pro
  • Pandas:merge_asof() 对多行求和/不重复

    我正在处理两个数据集 每个数据集具有不同的关联日期 我想合并它们 但因为日期不完全匹配 我相信merge asof 是最好的方法 然而 有两件事发生merge asof 不理想的 数字重复 数字丢失 以下代码是一个示例 df a pd Da
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 如何计算 pandas 数据帧上的连续有序值

    我试图从给定的数据帧中获取连续 0 值的最大计数 其中包含来自 pandas 数据帧的 id date value 列 如下所示 id date value 354 2019 03 01 0 354 2019 03 02 0 354 201
  • Scrapy:如何使用元在方法之间传递项目

    我是 scrapy 和 python 的新手 我试图将 parse quotes 中的项目 item author 传递给下一个解析方法 parse bio 我尝试了 request meta 和 response meta 方法 如 sc
  • 导入错误:没有名为 site 的模块 - mac

    我已经有这个问题几个月了 每次我想获取一个新的 python 包并使用它时 我都会在终端中收到此错误 ImportError No module named site 我不知道为什么会出现这个错误 实际上 我无法使用任何新软件包 因为每次我
  • neo4j - python 驱动程序,服务不可用

    我对 neo4j 非常陌生 我正在尝试建立从 python3 6 到 neo4j 的连接 我已经安装了驱动程序 并且刚刚开始执行第一步 导入请求 导入操作系统 导入时间 导入urllib 从 neo4j v1 导入 GraphDatabas
  • 如何使用 Pycharm 安装 tkinter? [复制]

    这个问题在这里已经有答案了 I used sudo apt get install python3 6 tk而且效果很好 如果我在终端中打开 python Tkinter 就可以工作 但我无法将其安装在我的 Pycharm 项目上 pip
  • 如何将输入读取为数字?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 Why are x and y下面的代码中使用字符串而不是整数 注意 在Python 2
  • NotImplementedError:无法将符号张量 (lstm_2/strided_slice:0) 转换为 numpy 数组。时间

    张量流版本 2 3 1 numpy 版本 1 20 在代码下面 define model model Sequential model add LSTM 50 activation relu input shape n steps n fe

随机推荐

  • 数字格式,写1e-5而不是0.00001

    我用过read table读取包含数字 例如 0 00001 的文件 当我写回它们时write table这些数字显示为 1e 5 如何保留旧格式 我只想改变scipen呼叫前的选项write table 请注意 这也会改变打印到控制台时数
  • Eclipse 中的 ESlint

    我在工作中得到了一个 Web 项目 其中有一个 eslintrc 文件 并被告知使用它 我认为这会强制执行代码样式 听起来是个好主意 但我以前从未这样做过 我刚刚切换到 Eclipse Neon 但我找不到有关如何使用它的教程 我确实发现了
  • HTTP 状态 500 - 过滤器执行引发异常 - doFilter 和 invokeDelegate 重复

    我正在使用 Spring MVC 4 2 5 和 Spring Security 4 1 3 来开发 Web 应用程序 当我尝试将后者合并到我的 mvc 项目中时 我开始遇到问题 目前 经过多次尝试 我在 localhost 8080 Be
  • Google 搜索 API 网站限制

    根据 Google 自定义搜索 API 文档 http code google com apis customsearch docs start html sites http code google com apis customsear
  • Node.js 的编码错误

    我正在用node js 重写一个小的python 脚本 原来的脚本是这样工作的 coding utf 8 import urllib import httplib import json def rpc url args try post
  • boost::asio 干净地断开连接

    有时 boost asio 似乎在我想要之前断开连接 即在服务器正确处理断开连接之前 我不确定这是怎么可能的 因为客户端似乎认为它完全发送了消息 但是当服务器发出错误时 它甚至没有读取消息头 在测试期间 这种情况可能只发生五分之一 服务器收
  • C++ 如何生成随机路径

    我正在尝试编写一个函数 可以为给定的二维点数组 x y 生成随机路径 现在 该路径有一些我希望它满足的要求才能使其有效 路径cannot 是从点开始的一条直线A to B 自行返回但可以倒退 如下所示 平行 沿着自身运行 我还想确保路径从左
  • android尺寸之间的区别:pt和dp

    文档称 160 dp 与密度无关 等于 1 英寸 72 pt 也是 1 英寸 所以我不明白为什么 android 定义 dp 测量 而它似乎与点一样工作 有人能解释一下吗 如果可以使用 pt 为什么还要使用 dp Android 文档曾经错
  • javax.faces.component.StateHolderSaver 可能存在内存泄漏

    我们最近将一个应用程序从 Jboss EAP 6 1 迁移到 7 1 我们的应用程序随机开始进入完整的 GC 死亡螺旋 平均时间 12 秒停止世界 并在生产环境中耗尽内存 我们从 Jboss EAP 6 1 迁移到 7 1 Java从7到8
  • SQLite“插入或替换为”不起作用

    我必须在 sqlite 中编写一个查询来更新记录 如果存在 或插入它 如果记录尚不存在 我看过的语法INSERT OR REPLACE INTO from here https stackoverflow com questions 225
  • 隐藏散点图中绘制线上方的所有点

    绘制 2 个星系等效宽度比列表 我将它们相互绘制 然后我想消除该线上方的所有点y 0 61 x 0 05 1 3这样图中就只剩下下面的点了 这是我到目前为止所拥有的 我已经查看了堆栈溢出 但不知道如何实现这一点 注 我只想要上面的几点y n
  • 如何动态添加类方法?

    使用 Objective C Runtime 如何添加方法 layerClass给私人UIGroupTableViewCellBackground类 不是它的超类 UIView 注意 这仅用于测试 看看如何UITableViewStyleG
  • python:从字典中创建直方图

    我是 python 新手 正在学习如何以正确的方式做事 我有字典列表d 每个字典代表用户 包含user id 年龄等信息 这个列表d可以包含代表同一用户的多个字典 但信息略有不同 这对我的目的来说并不重要 我想创建直方图来显示有多少用户d与
  • Java 中是否有类似于 C# 匿名类型的功能?

    我想知道 Java 中是否存在类似于 C 匿名类型的类似功能 var a new Count 5 Message A string 或者这个概念违背了Java范式 EDIT 我想使用Hashable Java 中的情况有些类似 不 没有同等
  • LinkedIn iOS SDK 捆绑包后缀

    因此 我的 LinkedIn 应用帐户上有多个捆绑包标识符 对于其中每一个 我还创建了一个 URL 后缀方案 我设置 URL 类型的方式就像li appID suffix where appID 是 LinkedIn 上提供的应用程序 ID
  • 强制 Linq 不延迟执行

    其实这个问题和这篇文章是同一个问题 如何确保 LINQ 查询在 DAL 中调用时执行 而不是以延迟方式执行 https stackoverflow com q 1013201 75642 但既然他没有解释why他想要它 这个问题似乎被忽略了
  • 在R中使用grepl来匹配字符串

    我有一个帧数据 testData 如下 id content 1 I came from China 2 I came from America 3 I came from Canada 4 I came from Japan 5 I ca
  • 这段代码是否颠覆了 C++ 类型系统?

    我明白有一个constC 中的方法意味着对象通过该方法是只读的 但否则它仍然可能会发生变化 然而 这段代码显然通过const参考 即通过const方法 这段代码在 C 中合法吗 如果是这样 是否违反了const 类型系统的性质 为什么 为什
  • Web 服务显示 Jquery 令牌输入结果的正确响应应该是什么?

    我正在使用 Jquery 令牌输入插件 我尝试从数据库而不是本地数据中获取数据 我的 Web 服务返回的 json 结果封装在 xml 中
  • 为什么类定义的元类关键字参数接受可调用对象?

    背景 蟒蛇3文档 https docs python org 3 6 reference datamodel html determining the appropriate metaclass清楚地描述了类的元类是如何确定的 如果没有给出