如何对“ super()”进行故障排除。

发布于 2025-01-17 13:49:44 字数 1497 浏览 4 评论 0原文

我的库中有一个装饰器,该装饰符上用户的类并创建了一个新版本,并使用新的元素段,应该完全替换原始类。一切都起作用;除super()调用外:

class NewMeta(type):
 pass

def deco(cls):
 cls_dict = dict(cls.__dict__)
 if "__dict__" in cls_dict:
   del cls_dict["__dict__"]
 if "__weakref__" in cls_dict:
   del cls_dict["__weakref__"]
 return NewMeta(cls.__name__, cls.__bases__, cls_dict)

@deco
class B:
 def x(self):
  print("Hi there")

@deco
class A(B):
 def x(self):
  super().x()

使用此代码,会产生错误:

>>> a = A()
>>> a.x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in x
TypeError: super(type, obj): obj must be an instance or subtype of type

某些术语:

  • 源代码类aa(b)类产生:
  • newmeta(Cls .__ name__,cls .__ bases__,cls_dict)生成的类别的类a*

A由Python建立为type当在a*a*的方法中使用super时。我该如何纠正?

有一些次优的解决方案,例如调用super(type(self),self).x,或通过cls .__ mro __而不是cls .__ bases __ bases __进入newMeta呼叫(以便obj = self总是从错误的type = a)继承。对于最终用户来说,第一个是不可持续的,第二个污染了继承链,并且由于班级似乎从自身继承而感到困惑。

Python似乎是内省的源代码,或者可能存储一些信息以自动建立type,在这种情况下,我会说它没有做到;

我如何确保在a A*的方法内建立为type gongeless grognless super super 呼叫?

I have a decorator in my library which takes a user's class and creates a new version of it, with a new metaclass, it is supposed to completely replace the original class. Everything works; except for super() calls:

class NewMeta(type):
 pass

def deco(cls):
 cls_dict = dict(cls.__dict__)
 if "__dict__" in cls_dict:
   del cls_dict["__dict__"]
 if "__weakref__" in cls_dict:
   del cls_dict["__weakref__"]
 return NewMeta(cls.__name__, cls.__bases__, cls_dict)

@deco
class B:
 def x(self):
  print("Hi there")

@deco
class A(B):
 def x(self):
  super().x()

Using this code like so, yields an error:

>>> a = A()
>>> a.x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in x
TypeError: super(type, obj): obj must be an instance or subtype of type

Some terminology:

  • The source code class A as produced by class A(B):.
  • The produced class A*, as produced by NewMeta(cls.__name__, cls.__bases__, cls_dict).

A is established by Python to be the type when using super inside of the methods of A*. How can I correct this?

There's some suboptimal solutions like calling super(type(self), self).x, or passing cls.__mro__ instead of cls.__bases__ into the NewMeta call (so that obj=self always inherits from the incorrect type=A). The first is unsustainable for end users, the 2nd pollutes the inheritance chains and is confusing as the class seems to inherit from itself.

Python seems to introspect the source code, or maybe stores some information to automatically establish the type, and in this case, I'd say it is failing to do so;

How could I make sure that inside of the methods of A A* is established as the type argument of argumentless super calls?

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

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

发布评论

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

评论(1

荒路情人 2025-01-24 13:49:44

无参数super使用__类__单元格,这是常规函数闭合。

数据模型:创建类别对象

__类__是编译器创建的隐式闭合引用,如果类正文中的任何方法请参阅__类__类__super。 P>

>>> class E:
...    def x(self):
...        return __class__  # return the __class__ cell
...
>>> E().x()
__main__.E
>>> # The cell is stored as a __closure__
>>> E.x.__closure__[0].cell_contents is E().x() is E
True

像任何其他关闭一样,这是词汇关系:它是指从字面上定义该方法的class范围。用装饰师代替班级仍然具有原始类的方法。


最简单的修复方法是明确提及类的名称,该名称 由装饰者反弹到新创建的类。

@deco
class A(B):
    def x(self):
        super(A, self).x()

另外,人们可以更改__类__单元格的内容以指向新类:

def deco(cls):
    cls_dict = dict(cls.__dict__)
    cls_dict.pop("__dict__", None)
    cls_dict.pop("__weakref__", None)
    new_cls = NewMeta(cls.__name__, cls.__bases__, cls_dict)
    for method in new_cls.__dict__.values():
        if getattr(method, "__closure__", None) and method.__closure__[0].cell_contents is cls:
            method.__closure__[0].cell_contents = new_cls
    return new_cls

The argument-free super uses the __class__ cell, which is a regular function closure.

Data Model: Creating the class object

__class__ is an implicit closure reference created by the compiler if any methods in a class body refer to either __class__ or super.

>>> class E:
...    def x(self):
...        return __class__  # return the __class__ cell
...
>>> E().x()
__main__.E
>>> # The cell is stored as a __closure__
>>> E.x.__closure__[0].cell_contents is E().x() is E
True

Like any other closure, this is a lexical relation: it refers to class scope in which the method was literally defined. Replacing the class with a decorator still has the methods refer to the original class.


The simplest fix is to explicitly refer to the name of the class, which gets rebound to the newly created class by the decorator.

@deco
class A(B):
    def x(self):
        super(A, self).x()

Alternatively, one can change the content of the __class__ cell to point to the new class:

def deco(cls):
    cls_dict = dict(cls.__dict__)
    cls_dict.pop("__dict__", None)
    cls_dict.pop("__weakref__", None)
    new_cls = NewMeta(cls.__name__, cls.__bases__, cls_dict)
    for method in new_cls.__dict__.values():
        if getattr(method, "__closure__", None) and method.__closure__[0].cell_contents is cls:
            method.__closure__[0].cell_contents = new_cls
    return new_cls
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文