tags:

views:

83

answers:

2

Hi,

consider following example:

class A():
    def __init__(self):
        self.veryImportantSession = 1

a = A()
a.veryImportantSession = None # ok

# 200 lines below
a.veryImportantSessssionnnn = 2 # I wanna exception here!! It is typo!

How could I make it so, that exception will be raised it case of I will try to set member that is not set in init?

Code above won't fail when it will be executed, but gives me fun time to debug problems.

Like with str:

>>> s = "lol"
>>> s.a = 1
>>> s.a = 1
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'str' object has no attribute 'a'

Thanks!

+3  A: 

You could override _setattr_ to only allow attribute names from a defined list.

class A(object):
    def __setattr__(self, name, value):
        allowed = ('x',)
        if name in allowed:
            self.__dict__[name]  = value
        else:
            raise AttributeError('No attribute: %s' % name) 

In operation:

>>> a = A()
>>> a.x = 5
>>> a.other = 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "myc.py", line 7, in __setattr__
    raise AttributeError('No attribute: %s' % name)
AttributeError: No attribute: other   

However, as msw has commented, attempts to make Python behave more like Java or C++ are usually a bad idea and will lead to losing lots of the benefits that Python provides. If you are concerned about making typos that might be missed then you are much better spending time writing unit tests for your code than trying to lock down the usage of your classes.

mikej
Agreed w/ unit tests, but is it really best way to avoid typos?
Stipa
A combination of unit tests and other kinds of automated tests. e.g. using your example from the comments on the question itself, if there was a test that checked the state of your session before and after an operation you would be able to tell if `superImportantSession` had not been set correctly.
mikej
@Stipa: I'd say so, as You would have to do two same typos. Something like typo during both variable declaration and setter.
Almad
There are lots of cases where it's very useful for user code to be able to assign arbitrary attributes to classes, without the class itself caring about them. This would break that for no reason. Also remember that this will only catch anything at runtime, not compile-time. Don't do this unless you have a specific reason to.
Glenn Maynard
+2  A: 

You can define a class variable called __slots__. See the Language Reference for more information.

__slots__ only work in new-style classes, so you need class A(object) instead of class A in this example.

class A(object):
    __slots__ = ['x']
    def __init__(self):
        self.x = 1

>>> a = A()
>>> a.x = 2
>>> a.y = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'y'
Baffe Boyois
`__slots__` is for memory optimization and should very rarely be used. Using it to "protect against typos" is misusing it--please don't recommend it for this purpose. Novices won't understand what they're breaking--for example, this silently broke weakrefs.
Glenn Maynard