Python对象 - 避免创建具有未知名称的属性

时间:2012-03-10 11:20:45

标签: python object attributes

希望避免这样的情况:

>>> class Point:
x = 0
y = 0
>>> a = Point()
>>> a.X = 4 #whoops, typo creates new attribute capital x

我创建了以下用作超类的对象:

class StrictObject(object):
    def __setattr__(self, item, value):
        if item in dir(self):
            object.__setattr__(self, item, value)
        else:
            raise AttributeError("Attribute " + item + " does not exist.")

虽然这似乎有效,但是documentation says of dir()

  

注意:因为提供dir()主要是为了方便在交互式提示下使用,它会尝试提供一组有趣的名称,而不是试图提供严格或一致的名称定义的名称集,其详细行为可能会在不同版本中发生变化。例如,当参数是类时,元类属性不在结果列表中。

是否有更好的方法来检查对象是否具有属性?

4 个答案:

答案 0 :(得分:16)

更好的方法。

最常见的方式是“我们都同意成年人”。这意味着,您不进行任何检查,并将其留给用户。你做的任何检查都会使代码的使用变得不那么灵活。

但是如果你真的想这样做,Python 3.x中默认为__slots__,Python 2.x中为新式类:

  

默认情况下,旧式和新式类的实例都有一个属性存储字典。这会浪费具有很少实例变量的对象的空间。在创建大量实例时,空间消耗会变得很严重。

     

可以通过在新样式类定义中定义__slots__来覆盖默认值。 __slots__声明采用一系列实例变量,并在每个实例中保留足够的空间来保存每个变量的值。保存空间是因为没有为每个实例创建__dict__

     

如果没有__dict__变量,则无法为实例分配__slots__定义中未列出的新变量。尝试分配到不公开的变量名称会引发AttributeError。如果需要动态分配新变量,则将'__dict__'添加到__slots__声明中的字符串序列。

例如:

class Point(object):
    __slots__ = ("x", "y")

point = Point()
point.x = 5 # OK
point.y = 1 # OK
point.X = 4 # AttributeError is raised

最后,检查对象是否具有某个属性的正确方法不是使用dir,而是使用内置函数hasattr(object, name)

答案 1 :(得分:2)

我认为编写代码以防止此类错误并不是一个好主意。这些“静态”检查应该是IDE的工作。 Pylint会警告您在__init__之外分配属性,从而防止拼写错误。它还显示了许多其他问题和潜在问题,可以很容易地从PyDev中使用。

答案 2 :(得分:2)

在这种情况下,你应该看看python标准库可能为你提供什么。你考虑过这个名字吗?

from collections import namedtuple

Point = namedtuple("Point", "x, y")

a = Point(1,3)

print a.x, a.y

因为Point现在是不可改变的,所以你的问题不可能发生,但是回归自然是你不可能的。只需为a添加+1,但必须创建一个完整的新实例。

x,y = a
b = Point(x+1,y)

答案 3 :(得分:0)

尝试一下:

from pystrict import strict

@strict
class Point:
   x = 0
   y = 0

a = Point()

a.X = 4