扩展memoized类的python会产生编译错误

时间:2018-01-31 14:21:20

标签: python memoization

我放弃了一个班级的记忆,作为一个我不想探索的包虫,这里有一个例子。我问的问题是"如何从一个记忆的类中扩展或继承"但我很可能犯了一个错误。下面的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

1 个答案:

答案 0 :(得分:0)

这个&#34;食谱&#34;确实是一个非常糟糕的主意 - 一旦你将Foo重新绑定到memoize(Foo)Foo就是memoize个实例,而不再是Foo类。这打破了所有期望wrt / python&#39; 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实例(这被命名为&#39;元类&#39; - 类的类 - 而type是默认的元类)。

因此,Foo现在是memoize个实例,而不是Type个实例,因为memoize不是一个合适的元类(它是{{1}方法签名是不兼容的),整件事情都行不通。

要使这一点发挥作用,您必须使__init__成为一个合适的元类(这是一个简单的例子,假设一个名为memoize的arg,但如果你想要它可以推广):

param