当前位置: 首页 > 面试题库 >

如何记住Python中的类实例?

终睿
2023-03-14
问题内容

好的,这是真实的情况:我正在编写一个应用程序,并且有一个表示某种类型文件的类(在我的情况下,这是照片,但是细节与问题无关)。Photograph类的每个实例对于照片的文件名应该是唯一的。

问题是,当用户告诉我的应用程序加载文件时,我需要能够确定文件何时已加载,并使用该文件名的现有实例,而不是在同一文件名上创建重复的实例。

对我来说,使用记忆化似乎是一种好情况,并且有很多这样的例子,但是在这种情况下,我不仅要记忆一个普通的函数,还需要记忆化__init__()。这带来了一个问题,因为到了__init__()被调用的时间,已经太晚了,因为已经创建了一个新实例。

在我的研究中,我发现了Python的__new__()方法,实际上我可以编写一个简单的示例,但是当我尝试在现实世界的对象上使用它时,它就崩溃了,我不确定为什么(我唯一能做的我认为现实世界中的对象是我无法真正控制的其他对象的子类,因此这种方法存在一些不兼容之处。这就是我所拥有的:

class Flub(object):
    instances = {}

    def __new__(cls, flubid):
        try:
            self = Flub.instances[flubid]
        except KeyError:
            self = Flub.instances[flubid] = super(Flub, cls).__new__(cls)
            print 'making a new one!'
            self.flubid = flubid
        print id(self)
        return self

    @staticmethod
    def destroy_all():
        for flub in Flub.instances.values():
            print 'killing', flub


a = Flub('foo')
b = Flub('foo')
c = Flub('bar')

print a
print b
print c
print a is b, b is c

Flub.destroy_all()

哪个输出:

making a new one!
139958663753808
139958663753808
making a new one!
139958663753872
<__main__.Flub object at 0x7f4aaa6fb050>
<__main__.Flub object at 0x7f4aaa6fb050>
<__main__.Flub object at 0x7f4aaa6fb090>
True False
killing <__main__.Flub object at 0x7f4aaa6fb050>
killing <__main__.Flub object at 0x7f4aaa6fb090>

这是完美的!对于给定的两个唯一ID,仅创建了两个实例,而Flub.instances显然仅列出了两个。

但是,当我尝试对正在使用的对象采用这种方法时,我遇到了各种愚蠢的错误,即__init__()仅接受0个参数而不是2个参数。所以我会改变一些方法,然后告诉我__init__()需要一个参数。完全奇怪。

经过一段时间的抗争之后,我基本上只是放弃了所有的__new__()黑魔法,并将其转移到称为的静态方法中get,这样我就可以调用Photograph.get(filename)它,并且只有Photograph(filename)在filename不存在时才调用它Photograph.instances

有人知道我在哪里出问题了吗?有什么更好的方法吗?

另一种思考方式是,它类似于单例,只是它不是全局单例,而是每个文件名单例。

这是我使用static方法get的实际代码,如果您想一起看一看的话。


问题答案:

让我们看看关于您的问题的两点。

您可以使用备忘录,但是您应该修饰 ,而不是__init__方法。假设我们有这个记忆器:

def get_id_tuple(f, args, kwargs, mark=object()):
    """ 
    Some quick'n'dirty way to generate a unique key for an specific call.
    """
    l = [id(f)]
    for arg in args:
        l.append(id(arg))
    l.append(id(mark))
    for k, v in kwargs:
        l.append(k)
        l.append(id(v))
    return tuple(l)

_memoized = {}
def memoize(f):
    """ 
    Some basic memoizer
    """
    def memoized(*args, **kwargs):
        key = get_id_tuple(f, args, kwargs)
        if key not in _memoized:
            _memoized[key] = f(*args, **kwargs)
        return _memoized[key]
    return memoized

现在,您只需要装饰类:

@memoize
class Test(object):
    def __init__(self, somevalue):
        self.somevalue = somevalue

让我们看看测试?

tests = [Test(1), Test(2), Test(3), Test(2), Test(4)]
for test in tests:
    print test.somevalue, id(test)

输出如下。请注意,相同的参数会产生与返回对象相同的ID:

1 3072319660
2 3072319692
3 3072319724
2 3072319692
4 3072319756

无论如何,我希望创建一个函数来生成对象并对其进行记忆。对我来说似乎更干净,但这可能与宠物无关紧要:

class Test(object):
    def __init__(self, somevalue):
        self.somevalue = somevalue

@memoize
def get_test_from_value(somevalue):
    return Test(somevalue)

使用__new__

或者,当然,您可以覆盖__new__。几天前,我发布了有关覆盖的内在,外在和最佳实践的答案,__new__这可能会有所帮助。基本上,它说总是传递*args, **kwargs给您的__new__方法。

对于一个人,我更愿意记住一个创建对象的函数,或者甚至编写一个特定的函数来避免从不将对象重新创建为相同的参数。当然,这主要是我的看法,而不是常规。



 类似资料:
  • 考虑以下代码: 在上面的例子中,当我尝试arr2[0]=a时,我得到了ArrayStoreException。这意味着数组会记住它必须接受的类型。但是列表不记得它们。它只是简单地编译并运行良好。当我检索对象BB时,将抛出ClassCastException。 所以问题是: > 数组如何记住它的类型(我知道它被称为“具体化”)。这到底是怎么发生的? 为什么只有数组被赋予这种能力,而不是ArrayLi

  • 问题内容: 我有一个登录页面,我想添加“记住我”功能;因此,如果用户注销并再次打开页面,则会加载其用户名和密码。为此,当用户登录(并选中“记住我”)时,我保存了以下cookie: 问题是稍后(在同一会话中)我阅读了cookie,然后看到maxAge = -1; 即使我将其设置为3600 …为什么呢?另一个问题:如果我使用userCookie.setSecure(true)将cookie设置为安全,

  • 问题内容: 我正在写一个轻量级的类,其属性旨在可公开访问,并且有时仅在特定的实例中被覆盖。就此而言,Python语言中没有为类属性或任何类型的属性创建文档字符串的规定。记录这些属性的预期方式和受支持方式是什么?目前,我正在做这种事情: 这将导致该类的docstring包含初始的标准docstring部分,以及通过对的扩展分配为每个属性添加的行。 尽管在文档字符串样式指南中似乎并未明确禁止使用这种样

  • 问题内容: 因此,我已经构建了该程序来构建不同的楼梯案例。本质上,问题是:给定整数N,您可以建立楼梯的几种不同方式。确保N大于3且小于200。任何先前的步骤都不能大于其后续步骤,否则会破坏楼梯的目的。 所以给定N = 3,您可以建立一个楼梯:2步,然后再步1步 给定N = 4,您可以建立一个楼梯:3步,然后再步1步 给定N = 5,您可以构建两个楼梯:3步,然后2步,或4步,然后1步。 我的方法在

  • 假设我们有一个类,如下所示: 因此,在这里,我需要以某种方式存储容器的类型(或)。我知道在我的程序的这一点,它是完全确定的。我需要存储它,因为稍后我可能不得不将我的强制转换回或,例如在另一个函数中: 我考虑过使用包含所有不同受支持类型的值的并将该类型保存在该枚举类型的附加成员变量中。然后,我必须使用语句来检查所有不同的可能性并执行正确的强制转换。但是,我想是不是没有更简单的方法。 我主要想做的是存

  • 本文向大家介绍JavaWeb 中Cookie实现记住密码的功能示例,包括了JavaWeb 中Cookie实现记住密码的功能示例的使用技巧和注意事项,需要的朋友参考一下 本文主要内容: •1、什么是Cookie •2、Cookie带来的好处 •3、Cookie的主要方法  一、什么是Cookie cookie是一种WEB服务器通过浏览器在访问者的硬盘上存储信息的手段。Cookie的目的就是为用户带来