用类包装器和__new__装饰类

时间:2017-01-31 11:41:58

标签: python-3.x

代码:

import functools


class MyInt1(int):

    def __new__(cls, x, value):
        print("MyInt1.__new__", cls, x, value)
        return super().__new__(cls, x, base=2)

    def __init__(self, x, value):
        print("MyInt1.__init__", self, x, value)
        self.value = value
        super().__init__()


class MyInt2:

    def __init__(self, x, value):
        print("MyInt2.__init__", self, x, value)
        self.value = value


def decorator(class_):

    class Wrapper(class_):

        def __new__(cls, *args, **kwargs):
            print("Wrapper.__new__", cls, args, kwargs)
            obj = super().__new__(cls, *args, **kwargs)
            ...
            return obj

        def __init__(self, *args, **kwargs):
            print("Wrapper.__init__", self, args, kwargs)
            functools.update_wrapper(self, class_)
            super().__init__(*args, **kwargs)

    return Wrapper


c = decorator(MyInt1)("101", 42)
print(c, c.value)
c = decorator(MyInt2)("101", 42)
print(c, c.value)

输出:

Wrapper.__new__ <class '__main__.decorator.<locals>.Wrapper'> ('101', 42) {}
MyInt1.__new__ <class '__main__.decorator.<locals>.Wrapper'> 101 42
Wrapper.__init__ 5 ('101', 42) {}
MyInt1.__init__ 5 101 42
5 42
Wrapper.__new__ <class '__main__.decorator.<locals>.Wrapper'> ('101', 42) {}
Traceback (most recent call last):
  File "tmp2.py", line 42, in <module>
    c = decorator(MyInt2)("101", 42)
  File "tmp2.py", line 28, in __new__
    obj = super().__new__(cls, *args, **kwargs)
TypeError: object() takes no parameters
  • 如果我不知道哪个班级传递给装饰师,应如何处理?
  • 为什么它不适用于常见模式?
  • 为什么默认__new__不接受__init__参数?

我找到的唯一方法是inspect.isbuiltin检查super().__new__并进行分支,但这很脏。

1 个答案:

答案 0 :(得分:1)

很难找到有关Python的基类(对象)行为的详细信息,这些行为是为了在创建新类时仅实现document.getElementById("testdiv").innerHTML = "<img src=" + test1.par2 + "alt=" + test1.par1 + " class='image' />"; 而实现的:

除了document.getElementById("testdiv").innerHTML = `<img src=${test1.par2} alt=${test1.par1} class='image' />`; __init__之外,

object自己的__init____new__方法不会引用任何争议。但是 - 如果从子类调用它们(碰巧是Python中定义的所有其他类) - 这些方法的每个方法都检查子类是否定义了一个而不是另一个(即,对象&#39; s {{ 1}}检查被实例化的类是否也定义了self

如果任何一个方法发现converse方法已被覆盖而且本身没有,它只是吞下任何额外的参数:因此用户的类cls可以有参数,而不用担心相同的参数 - 将传递给__init__将导致错误,

因此,您遇到的问题是,在此检查期间,例如,对象的__new__发现您的包装器已定义__init__ - 因此它不会吞下任何参数 - 和错误,因为有额外的论点。

修复它的唯一方法是,如果要保持这种模式,就是在装饰器中重新实现相同的逻辑:

object.__new__

https://mail.python.org/pipermail/python-list/2016-March/704027.html表明存在这种行为的暗示 - 我在官方文档中看起来似乎是这样,但在某些地方我不记得哪一个。