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

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(使用前将#替换为@)

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

  • Python模块可以访问英语词典,包括单词的定义[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个 python 模块 它可以帮助我从英语词典中获取单词的定义 当然有enchant 这可以帮助我检查该单词是否存在于英语中
  • Django 模型在模板中不可迭代

    我试图迭代模型以获取列表中的第一个图像 但它给了我错误 即模型不可迭代 以下是我的模型和模板的代码 我只需要获取与单个产品相关的列表中的第一个图像 模型 py class Product models Model title models
  • 为什么Python的curses中escape键有延迟?

    In the Python curses module I have observed that there is a roughly 1 second delay between pressing the esc key and getc
  • 在Python中调整图像大小

    我有一张尺寸为 288 352 的图像 我想将其大小调整为 160 240 我尝试了以下代码 im imread abc png img im resize 160 240 Image ANTIALIAS 但它给出了一个错误TypeErro
  • 奇怪的 MySQL Python mod_wsgi 无法连接到 'localhost' (49) 上的 MySQL 服务器问题

    StackOverflow上也有类似的问题 但我还没有发现完全相同的情况 这是在使用 MySQL 的 OS X Leopard 机器上 一些起始信息 MySQL Server version 5 1 30 Apache 2 2 13 Uni
  • 按元组分隔符拆分列表

    我有清单 print L I WW am XX newbie YY ZZ You WW are XX cool YY ZZ 我想用分隔符将列表拆分为子列表 ZZ print new L I WW am XX newbie YY ZZ You
  • 将 JSON 对象传递给带有请求的 url

    所以 我想利用 Kenneth 的优秀请求模块 https github com kennethreitz requests 在尝试使用时偶然发现了这个问题自由库API http wiki freebase com wiki API 基本上
  • Pandas 根据 diff 列形成簇

    我正在尝试使用 Pandas 根据表示时间 以秒为单位 的列中的差异来消除数据框中的一些接近重复项 例如 import pandas as pd numpy as np df pd DataFrame 1200 1201 1233 1555
  • 将 2D NumPy 数组按元素相乘并求和

    我想知道是否有一种更快的方法 专用 NumPy 函数来执行 2D NumPy 数组的元素乘法 然后对所有元素求和 我目前使用np sum np multiply A B 其中 A B 是相同维度的 NumPy 数组m x n 您可以使用np
  • 构造函数中显式关键字的使用

    我试图了解 C 中显式关键字的用法 并查看了这个问题C 中的explicit关键字是什么意思 https stackoverflow com questions 121162 但是 那里列出的示例 实际上是前两个答案 对于用法并不是很清楚
  • 无法在 osx-arm64 上安装 Python 3.7

    我正在尝试使用 Conda 创建一个带有 Python 3 7 的新环境 例如 conda create n qnn python 3 7 我收到以下错误 Collecting package metadata current repoda
  • 创建嵌套字典单行

    您好 我有三个列表 我想使用一行创建一个三级嵌套字典 i e l1 a b l2 1 2 3 l3 d e 我想创建以下嵌套字典 nd a 1 d 0 e 0 2 d 0 e 0 3 d 0 e 0 b a 1 d 0 e 0 2 d 0
  • 如何在 OSX 上安装 numpy 和 scipy?

    我是 Mac 新手 请耐心等待 我现在使用的是雪豹 10 6 4 我想安装numpy和scipy 所以我从他们的官方网站下载了python2 6 numpy和scipy dmg文件 但是 我在导入 numpy 时遇到问题 Library F
  • 使用 PyTorch 分布式 NCCL 连接失败

    我正在尝试使用 torch distributed 将 PyTorch 张量从一台机器发送到另一台机器 dist init process group 函数正常工作 但是 dist broadcast 函数中出现连接失败 这是我在节点 0
  • Tkinter - 浮动窗口 - 调整大小

    灵感来自this https stackoverflow com a 22424245 13629335问题 我想为我的根窗口编写自己的调整大小函数 但我刚刚注意到我的代码显示了一些性能问题 如果你快速调整它的大小 你会发现窗口没有像我希望
  • 如何为每个屏幕添加自己的 .py 和 .kv 文件?

    我想为每个屏幕都有一个单独的 py 和 kv 文件 应通过 main py main kv 中的 ScreenManager 选择屏幕 设计应从文件 screen X kv 加载 类等应从文件 screen X py 加载 Screens
  • 在Python中按属性获取对象列表中的索引

    我有具有属性 id 的对象列表 我想找到具有特定 id 的对象的索引 我写了这样的东西 index 1 for i in range len my list if my list i id specific id index i break
  • 检查字典键是否有空值

    我有以下字典 dict1 city name yass region zipcode phone address tehsil planet mars 我正在尝试创建一个基于 dict1 的新字典 但是 它不会包含带有空字符串的键 它不会包
  • Python 无法使用套接字绑定我的外部/公共 IP 地址,给出错误但是当使用本地 IP 地址时,错误不会显示

    这是出现主要错误的代码 与我的本地 IP 的绑定将起作用 s bind 192 168 1 4 port 与我的公共 IP 的绑定失败并出现以下错误 s bind 99 99 99 99 port WinError 10049 请求的地址在
  • Scrapy Spider不存储状态(持久状态)

    您好 有一个基本的蜘蛛 可以运行以获取给定域上的所有链接 我想确保它保持其状态 以便它可以从离开的位置恢复 我已按照给定的网址进行操作http doc scrapy org en latest topics jobs html http d

随机推荐

  • 数字格式,写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清楚地描述了类的元类是如何确定的 如果没有给出