__setattr__与__slots__用于约束Python中的属性创建

时间:2013-12-05 17:12:22

标签: python attributes slots setattr

我一直在阅读如何使Python类不那么动态,特别是不允许用户动态创建新属性。我读过overloadding __setattr__ is a good way to do this__slots__ is not the way to go。一个post on this last thread实际上表明__slots__可以打破酸洗。 (任何人都可以证实这一点吗?)

然而,我只是在阅读Python 2.2的whatsnew,而the attribute access section实际上建议使用__slots__来限制属性创建,而不仅仅是像其他人所建议的那样进行优化。就Python历史而言,有谁知道__slots__的初衷是什么?限制变量创建是一个特征还是一个被滥用的bug?人们如何看待__slots__在实践中使用?有很多人看到__setattr__重载以限制属性创建?哪一个最好?如果您对一种方法或另一种方法更熟悉,请随意发布您知道的方法的优缺点。此外,如果您有不同的解决方法,请分享! (请尽量不要重复other threads中表达的__slots__的缺点。)

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

EDIT 2,重新酸洗:这些物品将来会被我们想要储存,而酸洗似乎是一种很好的方法。如果__slots__显然是最好的解决方案,我们可能会找到另一种方法来存储它们,但酸洗肯定是有价值的,应该加以考虑。

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

2 个答案:

答案 0 :(得分:4)

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

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

如果有充分的理由限制它(再次,你确定有吗?)你需要保存那么一点内存,那就去__slots__。< / p>


阅读完解释后,您可能希望使用__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()来自this site的实施#4。如果不是那么聪明的用户,您可能希望使错误更加冗长并包含所有紧密匹配而不仅仅是第一个匹配。

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

答案 1 :(得分:1)

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