Consider the 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 an exception will be raised if I try to set a member that is not set in __init__
?
Code above won't fail when it is executed, but gives me a fun time to debug the problems.
Like with str:
>>> s = "lol"
>>> s.a = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'a'
Thanks!
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.
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'
The best way to protect against typos is to use a tool such as pyflakes or pylint -- these will go through your code and let you know if you have a variable a.superImportantSesssssionnnn
that is not ever used again, as well as many other things.
If you insist on doing it in code you have two options:
(ab)use __slots__
-- the primary purpose of __slots__
is memory optimization for those times when you will have hundreds, thousands, or millions of objects and you need to keep your objects' footprints as small as possible. If you go this route you should make sure and include __weakref__
as one of the allowed names so weak references will continue to work.
(ab)use __setattr__
-- the primary purpose of __setattr__
is to allow code to be run to validate, manipulate, or otherwise take the data given and put it in the correct format for storage
To reiterate, the above two options are not intended to be used as spell-checkers, and your efforts to limit the usefulness of your code by disallowing every possible attribute name except for those few you use yourself may not be appreciated when someone is trying to support a use-case you did not anticipate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With