首页 > 编程问答 >python 元类:在调用“__set_name__”方法后编辑命名空间?

python 元类:在调用“__set_name__”方法后编辑命名空间?

时间:2024-08-05 16:50:18浏览次数:10  
标签:python metaclass

假设我们用元类定义一个类。 在类主体中,分配了对象,这些对象实现 __set_name__ 以在类的数据结构中注册自身。

是否可以在运行方法之后编辑命名空间 ?比如,分离填充的数据结构,将其分成两部分,然后在新属性下添加部分? __set_name__ 问题在于,在元类中调用

之前,数据结构仍然是空的。之后它被填充,但是类已经创建了,它的命名空间现在是元类中构建的命名空间的只读副本。 super().__new__(...) 是否有机会编辑命名空间,并应用

方法,就像在被冻结到新类之前通过钩子一样? __set_name__ methods applied, like via a hook just before it is frozen into the new class?


你说的没错,在元类的 __new__ 方法中,通过 __set_name__ 注册信息后,直接修改类命名空间来分割数据结构是不可行的。因为此时返回给 Python 解释器的类对象已经生成,其命名空间变成了只读状态。

不过,我们可以通过一些技巧来实现类似的目的:

1. 利用描述符 (descriptor) 延迟数据结构的访问:

class MyMeta(type):
    def __new__(mcs, name, bases, attrs):
        registered_objects = {}
        for key, value in attrs.items():
            if hasattr(value, '__set_name__'):
                value.__set_name__(None, key)
                registered_objects[key] = value

        attrs['_registered_objects'] = registered_objects

        # 使用描述符延迟访问数据结构
        attrs['partitioned_data'] = PartitionedDataDescriptor(attrs)

        return super().__new__(mcs, name, bases, attrs)


class PartitionedDataDescriptor:
    def __init__(self, attrs):
        self.attrs = attrs

    def __get__(self, instance, owner):
        # 在访问时才进行数据结构分割
        part1 = {key: self.attrs['_registered_objects'][key] for key in ['attr1', 'attr2']}
        part2 = {key: self.attrs['_registered_objects'][key] for key in ['attr3', 'attr4']}
        return part1, part2


class MyClass(metaclass=MyMeta):
    attr1 = RegisteredObject()
    attr2 = RegisteredObject()
    attr3 = RegisteredObject()
    attr4 = RegisteredObject()

# ...
print(MyClass.partitioned_data)  # 访问时才会进行分割

这里我们创建了一个 PartitionedDataDescriptor 描述符,它在 __get__ 方法中动态地将 _registered_objects 分割成两部分并返回。这样就避免了直接修改类命名空间的问题。

2. 使用自定义元类方法,在类定义结束后修改:

class MyMeta(type):
    def __new__(mcs, name, bases, attrs):
        attrs['_registered_objects'] = {}
        return super().__new__(mcs, name, bases, attrs)

    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)
        for key, value in attrs.items():
            if hasattr(value, '__set_name__'):
                value.__set_name__(None, key)
                cls._registered_objects[key] = value

        # 在__init__方法中分割数据结构
        cls.part1 = {key: cls._registered_objects[key] for key in ['attr1', 'attr2']}
        cls.part2 = {key: cls._registered_objects[key] for key in ['attr3', 'attr4']}


class MyClass(metaclass=MyMeta):
    attr1 = RegisteredObject()
    attr2 = RegisteredObject()
    attr3 = RegisteredObject()
    attr4 = RegisteredObject()

# ...
print(MyClass.part1)
print(MyClass.part2) 

这里我们在元类的 __init__ 方法中进行数据结构分割。因为 __init__ 方法在类对象创建之后才被调用,所以此时修改类属性是可以的。

总而言之,虽然不能直接在 __set_name__ 执行后立即修改类命名空间,但通过描述符或自定义元类方法可以实现类似效果。选择哪种方法取决于你的具体需求和代码结构。

标签:python,metaclass
From: 78831535

相关文章

  • 无法加入进程,只能终止[Python 3.11,多处理]
    我有一个问题要问对Python的多处理库有更​​多经验的人,此时我几乎迷失了方向。我目前正在构建一个应该在Windows11和Windows11上运行的图像处理应用程序装有DebianLinux的OrangePi5。我的设置是,除了主程序之外,还有另外两个进程,一个用于处理不间断的......
  • Python 将Word转换为JPG、PNG、SVG图片
    将Word文档以图片形式导出,既能方便信息的分享,也能保护数据安全,避免被二次编辑。文本将介绍如何使用 Spire.DocforPython 库在Python程序中实现Word到图片的批量转换。Python将Word转换为JPG、JPEG、PNG、BMP等图片格式Python将Word文档转换为SVG格式 Python库安装: ......
  • C 和 Python 代码的函数的不同十六进制转储值
    这是我的示例C代码,用于从user32.dll中转储MessageBoxA:#include<windows.h>#include<stdio.h>voidDumpFun(HANDLEprocess,LPVOIDaddress,SIZE_Tdump_size){BYTE*buffer=(BYTE*)malloc(dump_size);if(buffer==NULL){pri......
  • 是否有对数累积分布函数 (CDF) 和分位数函数的数值稳定的 Python 实现?
    我正在寻找以下函数的数值稳定实现。由于我的应用涉及t分布,所以我这里以t分布为例。LogCDF#NaivePythonimplementationofthefunctionIneedimportscipyimportnumpyasnpdeft_log_cdf(x,df):p=scipy.stats.t.cdf(x,df=df)returnnp.log(......
  • 如何将 *args 参数作为字符串传递给 Python 函数
    我正在使用pytubefix制作一个Youtube下载器。API允许我编写如下代码:YouTube(url).streams.filter(progressive=True)但是假设我有一个字符串存储在像args="progressive=True"这样的变量中,我如何使用args字符串来调用函数,就像......
  • Python Telegram Bot 从数据库获取数据时出错
    我正在开发用于管理企业用途任务的电报机器人。团队负责人注册他的公司并获得唯一的ID,然后可以分配任务。问题是,当团队负责人分配任务时,他可以使用/viewtasks访问它们。但是,当员工尝试查看任务时,它会打印出“错误。您尚未注册”。似乎无法检索与用户关联的company_id,即使......
  • 在 Glue 作业中使用 python3+ 创建 CloudFront 签名 URL
    是否可以使用python3+为GlueJob中S3文件中的一个特定文件创建具有一定时间限制的CloudFront签名URL?我看到可以在Lambda中做到这一点,但在Python文档中找不到任何内容,特别是胶水工作。任何人都可以提供一些提示吗?defload_private_key(key_path):withopen(......
  • 【Python学习手册(第四版)】学习笔记14-迭代器和列表解析(一)
    个人总结难免疏漏,请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。本文主要以通俗易懂的语言介绍迭代器(文件迭代、手动迭代iter和next等),列表解析式包括基础知识包括写法、文件上使用列表解析、扩展列表解析语法等,对列表解析不懂的同学着重推荐......
  • 如何获取部署在 Azure 应用服务上并通过 Microsoft 身份提供商进行身份验证的 Python
    我使用PythonDash包构建了一个Web应用程序,并将该应用程序部署在Azure应用服务上。Web应用程序当前通过Azure门户的应用程序服务使用Microsoft身份提供程序进行身份验证。但是如何获取登录用户的详细信息呢?在本地运行时如何验证我的Web应用程序?我当前的登录流......
  • 使用 Python 打印此图案
    1010101010101010使用python打印此我已经尝试过defprint_pattern(rows):foriinrange(rows):start_char='1'ifi%2==0else'0'pattern=''.join(start_charifj%2==0else('0'ifs......