Python objects - avoiding creation of attribute with unknown name

I don't think it's a good idea to write code to prevent such errors. These "static" checks should be the job of your IDE. Pylint will warn you about assigning attributes outside of __init__ thus preventing typo errors. It also shows many other problems and potential problems and it can easily be used from PyDev.


Much better ways.

The most common way is "we're all consenting adults". That means, you don't do any checking, and you leave it up to the user. Any checking you do makes the code less flexible in it's use.

But if you really want to do this, there is __slots__ by default in Python 3.x, and for new-style classes in Python 2.x:

By default, instances of both old and new-style classes have a dictionary for attribute storage. This wastes space for objects having very few instance variables. The space consumption can become acute when creating large numbers of instances.

The default can be overridden by defining __slots__ in a new-style class definition. The __slots__ declaration takes a sequence of instance variables and reserves just enough space in each instance to hold a value for each variable. Space is saved because __dict__ is not created for each instance.

Without a __dict__ variable, instances cannot be assigned new variables not listed in the __slots__ definition. Attempts to assign to an unlisted variable name raises AttributeError. If dynamic assignment of new variables is desired, then add '__dict__' to the sequence of strings in the __slots__ declaration.

For example:

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

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

And finally, the proper way to check if an object has a certain attribute is not to use dir, but to use the built-in function hasattr(object, name).


In such situation you should look what the python standard library may offer you. Did you consider the namedtuple?

from collections import namedtuple

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

a = Point(1,3)

print a.x, a.y

Because Point is now immutable your problem just can't happen, but the draw-back is naturally you can't e.g. just add +1 to a, but have to create a complete new Instance.

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