Python __new__ 元类行为与继承

发布于 2024-11-23 20:12:59 字数 981 浏览 1 评论 0原文

我对运行以下代码的行为有两个问题。为什么__new__甚至在没有实例化对象的情况下被调用?我认为 __new__ 控制了新实例的创建。接下来,为什么当 hasattr 对于 size 返回 True 时,delattr 会引发 AttributeError

class ShapeBase(type):

  def __new__(cls, name, bases, attrs):
    rv = super(ShapeBase, cls).__new__(cls, name, bases, attrs)
    parents = [base for base in bases if isinstance(base, ShapeBase)]

    # don't do anything unless this is a subclass of Shape
    if not parents:
      return rv

    print hasattr(rv, 'altitude') # prints True
    print rv.altitude             # prints 7
    del rv.altitude               # deletes altitude from rv

    print hasattr(rv, 'size')     # prints True
    print rv.size                 # prints 5
    delattr(rv, 'size')           # raises AttributeError                    

    return rv

class Shape(object):
  __metaclass__ = ShapeBase
  size = 5

class Triangle(Shape):
  altitude = 7

I have two questions regarding the behavior of running the below code. Why is __new__ even being called without instantiating an object? I thought __new__ controlled the creation of a new instance. Next, why does delattr raise an AttributeError when hasattr returns True for size?

class ShapeBase(type):

  def __new__(cls, name, bases, attrs):
    rv = super(ShapeBase, cls).__new__(cls, name, bases, attrs)
    parents = [base for base in bases if isinstance(base, ShapeBase)]

    # don't do anything unless this is a subclass of Shape
    if not parents:
      return rv

    print hasattr(rv, 'altitude') # prints True
    print rv.altitude             # prints 7
    del rv.altitude               # deletes altitude from rv

    print hasattr(rv, 'size')     # prints True
    print rv.size                 # prints 5
    delattr(rv, 'size')           # raises AttributeError                    

    return rv

class Shape(object):
  __metaclass__ = ShapeBase
  size = 5

class Triangle(Shape):
  altitude = 7

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

荒芜了季节 2024-11-30 20:12:59

元类的 __new__ 控制新类的实例化,而不是该类的新实例。因此,当您创建以 ShapeBase 作为元类的 Shape 类时,将调用 ShapeBase.__new__

__new__ of a metaclass controls the instantiation of a new class, not a new instance of that class. So, when you create the class Shape with ShapeBase as the metaclass, ShapeBase.__new__ is invoked.

儭儭莪哋寶赑 2024-11-30 20:12:59

对于第二个问题,delattr(rv, 'size')(和 del rv.size)失败,因为属性 size 是一个类属性不是实例属性,这意味着它是类 __dict__ 的一部分,而不是实例 __dict__ 的一部分。

hasattr 通常会返回 True,因为它会在传递给它的对象的所有父类中搜索属性。

至于为什么在评估类主体时调用元类 __new__ ,可以这样想:

如果您创建类的实例,则在创建实例时将调用类__new__,是吗?所以这同样适用于 class ,元类是类的类,因此在创建类时将调用 __new__

For the second question delattr(rv, 'size') (and del rv.size) is failing because the attribute size is a class attribute not an instance attribute which mean is part of the class __dict__ not the instance __dict__.

And the hasattr normally will return True because it search for an attribute in all the parent classes of the object passed to it.

As for why your metaclass __new__ is called when the class body is evaluated think of it like this :

If you create an instance of a class the class __new__ will be called when you create the instance, yes ? so the same should apply on class , a metaclass is a class of a class so the __new__ will be called when you create the class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文