1

我一直在阅读有关如何使 Python 类不那么动态的文章,特别是不允许用户动态创建新属性。我读过重载__setattr__是一个很好的方法,而__slots__不是要走的路。最后一个帖子上的一篇文章实际上表明它__slots__可以破坏酸洗。(谁能证实这一点?)

但是,我只是在阅读 Python 2.2 的最新消息,而属性访问部分实际上建议将__slots__其用于约束属性创建的目的,而不仅仅是像其他人建议的那样进行优化。从 Python 的历史来看,有谁知道它的初衷__slots__是什么?约束变量创建是要被滥用的功能还是错误?人们__slots__在实践中是如何使用的?有很多人看到__setattr__过重载来限制属性创建吗?哪个最好?如果您更熟悉一种方法或另一种方法,请随时发布您所知道的方法的优缺点。另外,如果您有其他解决问题的方法,请分享!(请尽量不要只是重复__slots__已经在其他线程中表达过。)

编辑:我希望避免讨论“为什么?”,但第一个答案表明这会出现,所以我会在这里说明。在有问题的项目中,我们使用这些类来存储“配置信息”,允许用户使用他们的(用户的)参数设置对象的属性,然后将对象传递给程序的另一部分。对象不仅仅是存储参数,所以字典不起作用。我们已经让用户不小心输入了错误的属性名称,最终创建了一个新属性,而不是设置程序期望的属性之一。这未被检测到,因此用户认为他们正在设置参数但没有看到预期的结果。这让用户感到困惑,而且很难发现。

编辑 2,重新酸洗:这些对象将是我们将来想要存储的东西,酸洗似乎是一种很好的方法。如果__slots__显然是最好的解决方案,我们可能会找到另一种存储它们的方法,但酸洗肯定是有价值的,应该考虑在内。

编辑 3:我还应该提到,内存保护不是问题。很少会创建这些对象,因此节省的任何内存都可以忽略不计(例如 3-12 GB 机器上的 10 千字节)。

4

2 回答 2

4

您为什么要限制开发人员这样做?除了“我不希望他们这样做”之外,还有什么技术原因吗?如果没有,请不要这样做。

无论如何,使用__slots__可以节省内存(否__dict__),所以它是更好的解决方案。如果您的某些代码需要对象具有但您将无法使用它__dict__

如果有充分的理由限制它(再次,你确定有一个吗?)或者你需要节省那一点点内存,去__slots__.


阅读您的解释后,您可能想要使用__setattr__,可能与__slots__(无论如何您都需要将属性白名单存储在某处,因此您也可以使用它来节省内存)。这样您就可以显示一些更有用的信息,例如哪些类似的属性可用。一个可能的实现可能如下所示:

class Test(object):
    __slots__ = ('foo', 'bar', 'moo', 'meow', 'foobar')

    def __setattr__(self, name, value):
        try:
            object.__setattr__(self, name, value)
        except AttributeError:
            alts = sorted(self.__slots__, key=lambda x: levenshtein(name, x))
            msg = "object has no attribute '{}', did you mean '{}'?"
            raise AttributeError(msg.format(name, alts[0]))

我测试它的是这个站点levenshtein()的实现#4 。如果不是那么聪明的用户,您可能希望使错误更加详细,并包括所有接近的匹配项,而不仅仅是第一个匹配项。

您可以通过创建仅包含该__setattr__方法的 mixin 类来进一步改进代码。这样,您可以将代码保留在您的真实类之外,并__setattr__在必要时进行自定义(只需super(...).__setattr__(...)在 mixin 中使用而不是object.__setattr__

于 2013-12-05T17:16:51.710 回答
1

我对您的用例的建议是在使用 Python 的警告模块无法识别属性名称时使用__setattr__并发出警告。

于 2013-12-05T17:31:21.233 回答