【问题标题】:python extending a memoized class gives a compilation errorpython扩展一个memoized类会产生编译错误
【发布时间】:2018-07-10 16:41:44
【问题描述】:

我已经放弃了将课程记忆为一袋我不想探索的蠕虫,这里有一个例子说明原因。我问的问题是“如何扩展或继承记忆类”,但很可能我犯了一个错误。下面的 memoize 课程是brandizzi 在How can I memoize a class instantiation in Python? 中的课程的精简版,通过谷歌搜索主题发现更多涉及此类课程。

class memoize(object):
    def __init__(self, cls):
        self.cls = cls
        # I didn't understand why this was needed
        self.__dict__.update(cls.__dict__)

        # bit about static methods not needed

    def __call__(self, *args):
        try:
            self.cls.instances
        except:
            self.cls.instances = {}    
        key = '//'.join(map(str, args))
        if key not in self.cls.instances:
            self.cls.instances[key] = self.cls(*args)
        return self.cls.instances[key]

class Foo():
    def __init__(self,val):
        self.val = val

    def __repr__(self):
        return "{}<{},{}>".format(self.__class__.__name__,self.val,id(self))

class Bar(Foo):
    def __init__(self,val):
        super().__init__(val)

f1,f2,f3 = [Foo(i) for i in (0,0,1)]
print([f1,f2,f3])
b1,b2,b3 = [Bar(i) for i in (0,0,1)]
print([b1,b2,b3])

# produces exactly what I expect
# [Foo<0,3071981964>, Foo<0,3071982092>, Foo<1,3071982316>]
# [Bar<0,3071983340>, Bar<0,3071983404>, Bar<1,3071983436>]

Foo = memoize(Foo)
f1,f2,f3 = [Foo(i) for i in (0,0,1)]
print([f1,f2,f3])
b1,b2,b3 = [Bar(i) for i in (0,0,1)]
print([b1,b2,b3])

# and now Foo has been memoized so Foo(0) always produces the same object
# [Foo<0,3071725804>, Foo<0,3071725804>, Foo<1,3071726060>]
# [Bar<0,3071711916>, Bar<0,3071711660>, Bar<1,3071725644>]

# this produces a compilation error that I don't understand

class Baz(Foo):
    def __init__(self,val):
        super().__init__(val)

# Traceback (most recent call last):
#   File "/tmp/foo.py", line 49, in <module>
#     class Baz(Foo):
# TypeError: __init__() takes 2 positional arguments but 4 were given

【问题讨论】:

  • 这个“配方”确实是一个非常糟糕的主意——一旦你将Foo 重新绑定到memoize(Foo)Foo 就是一个memoize 实例,而不是Foo 类了。这打破了 wrt/python 的 type 和整个对象模型的所有期望。

标签: python memoization


【解决方案1】:

这个“配方”确实是一个非常糟糕的主意——一旦你将Foo 重新绑定到memoize(Foo)Foo 就是一个memoize 实例,而不是Foo 类了。这打破了 wrt/python 的 type 和整个对象模型的所有期望。在这种情况下,它是关于 class 语句的工作原理。其实是这样的:

class Titi():
    x = 42
    def toto(self):
        print(self.x)

是语法糖:

def toto(self):
    print(self.x)
Titi = type("Titi", (object,), {x:42, toto:toto})
del toto

请注意,这发生在运行时(就像 Python 中的所有内容一样,除了解析/字节码编译),并且 type 是一个类,因此调用 type 创建一个新类,它是一个 type 实例(这被命名为'metaclass' - 一个类的类 - 而type 是默认的元类)。

所以Foo 现在是memoize 实例而不是Type 实例,并且由于memoize 不是一个适当的元类(它的__init__ 方法签名不兼容),整个事情就是无法工作.

要使其工作,您必须使 memoize 成为适当的元类(这是一个简化的示例,假设有一个名为 param 的参数,但如果您愿意,可以对其进行概括):

class FooType(type):
    def __new__(meta, name, bases, attrs):
        if "_instances" not in attrs:
            attrs["_instances"] = dict()
        return type.__new__(meta, name, bases, attrs)

    def __call__(cls, param):
        if param not in cls._instances:
            cls._instances[param] = super(FooType, cls).__call__(param)
        return cls._instances[param]


class Foo(metaclass=FooType):
    def __init__(self, param):
        self._param = param
        print("%s init(%s)" % (self, param))

    def __repr__(self):
        return "{}<{},{}>".format(self.__class__.__name__, self._param, id(self))


class Bar(Foo):
    pass


f1,f2,f3 = [Foo(i) for i in (0,0,1)]
print([f1,f2,f3])
b1,b2,b3 = [Bar(i) for i in (0,0,1)]
print([b1,b2,b3])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多