希望避免这样的情况:
>>> 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()
主要是为了方便在交互式提示下使用,它会尝试提供一组有趣的名称,而不是试图提供严格或一致的名称定义的名称集,其详细行为可能会在不同版本中发生变化。例如,当参数是类时,元类属性不在结果列表中。
是否有更好的方法来检查对象是否具有属性?
答案 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