python扩展memoized类提供了一个编译

2024-05-11 22:35:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经放弃了把一门课当作一袋我不想探究的虫子的记忆,下面是一个例子。我问的问题是“如何扩展或继承一个记忆类”,但很可能我犯了一个错误。下面的memoize类是brandizzi在How can I memoize a class instantiation in Python?中创建的一个类的精简版本,通过google这个主题可以找到更多相关的类。你知道吗

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

Tags: instanceskeyinselffooinitdefbar
1条回答
网友
1楼 · 发布于 2024-05-11 22:35:47

这个“配方”确实是一个非常糟糕的主意-一旦你将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实例(这被称为“元类”—类的类,type是默认的元类)。你知道吗

因此,Foo现在是一个memoize实例,而不是一个Type实例,而且由于memoize不是一个合适的元类(它的__init__方法签名是不兼容的),整件事情就不能工作了。你知道吗

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

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])

相关问题 更多 >