In Python, Count The Number Of Variables In A Class Or Prevent Adding New Class Variables
Solution 1:
I suggest using __setattr__
to avoid the oddities of __slots__
.
You always have to be careful when messing with __setattr__
, since it takes care of setting all instance attributes, including those you set in __init__
. Therefore it has to have some way of knowing when to allow the setting of an attribute, and when to deny it. In this solution I've designated a special attribute that controls whether new attributes are allowed or not:
classA(object):
def__init__(self):
self.a = 1
self.b = 2
self.c = 3
self.freeze = Truedef__setattr__(self, attr, value):
ifgetattr(self, "freeze", False) andnothasattr(self, attr):
raise AttributeError("You shall not set attributes!")
super(A, self).__setattr__(attr, value)
Testing:
a = A()
try:
a.d = 89except AttributeError:
print"It works!"else:
print"It doesn't work."
a.c = 42print a.a
print a.c
a.freeze = False
a.d = 28
a.freeze = Trueprint a.d
Result:
It works! 1 42 28
Also see gnibblers answer that wraps this concept neatly up in a class decorator, so it doesn't clutter up the class definition and can be reused in several classes without duplicating code.
EDIT:
Coming back to this answer a year later, I realize a context manager might solve this problem even better. Here's a modified version of gnibbler's class decorator:
from contextlib import contextmanager
@contextmanagerdefdeclare_attributes(self):
self._allow_declarations = Truetry:
yieldfinally:
self._allow_declarations = Falsedefrestrict_attributes(cls):
cls.declare_attributes = declare_attributes
def_setattr(self, attr, value):
disallow_declarations = notgetattr(self, "_allow_declarations", False)
if disallow_declarations and attr != "_allow_declarations":
ifnothasattr(self, attr):
raise AttributeError("You shall not set attributes!")
super(cls, self).__setattr__(attr, value)
cls.__setattr__ = _setattrreturn cls
And here's how to use it:
@restrict_attributesclassA(object):
def__init__(self):
with self.declare_attributes():
self.a = 1
self.b = 2
self.c = 3
So whenever you want to set new attributes, just use the with
statement as above. It can also be done from outside the instance:
a = A()
try:
a.d = 89except AttributeError:
print"It works!"else:
print"It doesn't work."
a.c = 42print a.a
print a.c
with a.declare_attributes():
a.d = 28print a.d
Solution 2:
In python, is there a way to prevent adding new class variables after defining the object?
Yes. __slots__
. But do carefully read the notes.
Solution 3:
How about a class decorator based on lazyr's answer
deffreeze(cls):
_init = cls.__init__
definit(self, *args, **kw):
_init(self, *args, **kw)
self.freeze = True
cls.__init__ = init
def_setattr(self, attr, value):
ifgetattr(self, "freeze", None) and (attr=="freeze"ornothasattr(self, attr)):
raise AttributeError("You shall not set attributes!")
super(cls, self).__setattr__(attr, value)
cls.__setattr__ = _setattrreturn cls
@freezeclassfoo(object):
def__init__(self):
self.a = 1
self.b = 2
self.c = 3
bar = foo()
try:
bar.d = 4except Exception, e:
print"I want this to always print"
Solution 4:
Preventing adding new attibutes using
__slots__
class attribute:classfoo(object): __slots__ = ['a', 'b', 'c'] def__init__(self): self.a = 1 self.b = 2 self.c = 3 bar = foo() try: bar.d = 4except Exception as e: print(e,"I want this to always print")
Counting attributes:
print(len([attr for attr indir(bar) if attr[0] != '_' ]))
Solution 5:
use this to count no.of attributes of an instance:
>>> classfoo:
def__init__(self):
self.a = 1
self.b = 2
self.c = 3>>> bar=foo()
>>> bar.__dict__
{'a': 1, 'c': 3, 'b': 2}
>>> len(bar.__dict__) #returns no. of attributes of bar3
Post a Comment for "In Python, Count The Number Of Variables In A Class Or Prevent Adding New Class Variables"