【问题标题】:Why do I get an Error when creating an instanz of a class that has a metaclass为什么在创建具有元类的类的实例时会出现错误
【发布时间】:2022-01-09 17:01:26
【问题描述】:
class  Meta(type):
    def __new__(cls, class_name, bases, attrs):

        a={}
        for name, val in attrs.items():
            if name.startswith("__"):
                a[name] = val
            else:
                a[name.upper()] = val

        return(class_name, bases, a)

class D(metaclass=Meta):
    x = 5
    y = 8

    def hello (self):
        print("hi")

c = D()
c.hello

为什么会出现这个错误:

'tuple' 对象不可调用 第 20 行,在 c = D()

找不到有人可以帮助我的原因吗?

(代码基于https://www.youtube.com/watch?v=NAQEj-c2CI8的视频教学)

【问题讨论】:

  • 因为你的“元类”返回一个元组,而不是一个类。我猜你打算打电话给type
  • 是的,它返回一个元组,但为什么这不是一个问题youtube.com/watch?v=NAQEj-c2CI8
  • 我不是在看视频,但这对你来说是个问题,因为__new__ 需要返回对象实例,在元类的情况下是一个。类是可调用的,元组不是。
  • 整个代码在视频的末尾,这是有效的。您能告诉我如何更改代码以使其正常工作吗?
  • 我检查了那个视频的结尾。正如@jonrsharpe 建议的那样,该代码返回type 调用而不是元组。

标签: python class tuples metaclass


【解决方案1】:

元类__new__method 中的最后一行,内容为

return(class_name, bases, a)

返回一个简单的元组 - 它应该(实际上,在您评论的视频中,您获得了学习灵感)调用 typetype.__new__:生成一个新类,然后可以使用:

return type(class_name, bases, a)

虽然该视频是关于元类的第一次介绍,但 (1) 这是一个高级主题,实际上可以在 Python 中完成整个职业生涯,而无需编写元类;

(2) 在调用 type 而不是 type.__new__ 时,该视频在技术上并不正确:它可以工作,但它具有不同的效果,因为生成的类虽然在创建时进行了修改,但将具有常规type 作为它的元类 - 通过直接调用 type,所有对元类本身的引用(您的 sn-p 中的 Meta)都将被丢弃。如果改为调用super().__new__(cls, class_name, bases, a) ,则创建的类将是元类的实例(在此调用中以名称cls 传递),并且创建的类的所有子类(示例中为D)也将具有相同的元类,并通过此__new__ 方法创建。

关于您的实验的一个额外细节:您正在测试以双下划线 ("__") 开头的属性 - Python 编译过程会自动修改所有此类名称,(但名称“夹在”一对“ __") 包含类名本身作为前缀 - 所以如果 D 将具有 __x 属性,它将在元类中收到的 attrs dict 中显示为 _D__x -

我在链接的视频中看到了其中的示例;但是,这部分代码从未经过测试或验证:没有 __ 属性被证明可以保留。不过,它将保留保留的“魔术”名称为__init__。如前所述,该视频并非 100% 适合教学,因为作者本身似乎只是展示了他自己的一些实验。

关于您得到的特定错误的最后一条评论:无论元类 __new__ 方法 returns 被 Python 用作绑定到类语句中名称的对象(D in这个案例)。所以,D 变成了一个包含元组的“普通”变量,而不是一个新的类。当你执行D() 时,Python 会尝试调用该对象,并得到元组不可调用的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 2022-12-09
    • 1970-01-01
    • 2013-08-27
    相关资源
    最近更新 更多