On Feb 26, 9:48 pm, "Alan Isaac" <[EMAIL PROTECTED]> wrote: > I have a class whose instances should only receive attribute > assignments for attributes that were created at inititialization. > If slots are not appropriate, what is the Pythonic design for this?
Hi ! Even though a lot of people have argued against such a thing, I have been thinking about this last night and I have the following hack. Classes descending from SuspiciousObject below won't allow new attributes to be added to their instances apart from within trusted methods (i.e. methods decorated with @trustedmethod) Note: this is probably not of great interest but I've decided to share it since I did this as a result of reading this thread :) class LockableDict(dict): "A dict where addition of new keys can be prevented by setting the locked attribute" __slots__ = ('locked',) def __init__(self, locked=False): self.locked = locked def force_setitem(self, key, value): super(LockableDict, self).__setitem__(key, value) def __setitem__(self, key, value): if self.has_key(key) or not self.locked: self.force_setitem(key, value) else: raise KeyError, key def trustedmethod(f): def pf(self, *args, **kwargs): was_locked = self.__dict__.locked self.__dict__.locked = False try: return f(self, *args, **kwargs) finally: self.__dict__.locked = was_locked return pf class SuspiciousObject(object): def __new__(cls, *args, **kwargs): self = object.__new__(cls) super(SuspiciousObject, self).__setattr__('__dict__', LockableDict(locked=True)) return self def __setattr__(self, attr, value): try: self.__dict__[attr] = value except KeyError: raise AttributeError, "'%s' object has no attribute '%s" % (type(self).__name__, attr) # Instances of SuspiciousObject refuse anyone the right to create a new attribute apart from methods marked with the decorator @trustedmethod. # Example: class Foo(SuspiciousObject): @trustedmethod def __init__(self): self.bar = 2 self.baz = 'Hello' def foobar(self, v): self.fubar = v @trustedmethod def force_setattr(self, attr, val=None): setattr(self, attr, val) This would give something like: >>> foo=Foo() >>> foo.bar 2 >>> foo.baz 'Hello' >>> foo.baz="Bye" # works as foo.baz exists >>> foo.baz 'Bye' >>> foo.fubar=4 # won't be trusted ... AttributeError: 'Foo' object has no attribute 'fubar >>> setattr(foo, 'fubar', 4) # won't work either ... AttributeError: 'Foo' object has no attribute 'fubar >>> foo.__dict__['fubar']=4 # Neither will this ... KeyError: 'fubar' >>> foo.foobar(4) # Neither will this as foo.foobar is not a trusted method ... AttributeError: 'Foo' object has no attribute 'fubar >>> foo.force_setattr('fubar', 4) # this will work as force_setattr is trusted >>> foo.fubar 4 >>> # etc... By creating a custom metaclass for SuspiciousObject, it would be easy to make SuspiciousObjects trust their own methods by default instead of having to declare which method are trusted. -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list