Hi,
In another thread on this list I was reminded of types.SimpleNamespace. This is nice, but I wanted to create a bag class with constants that are read-only. My main question is about example #3 below (example #2 just illustrates my thought process). Is this a use case to a metaclass? Or can I do it some other way (maybe a class decorator?). I would like to create a metaclass that converts any non-special attributes (=not starting with '_') into properties, if needed. That way I can specify my bag class in a very clean way: I only specify the metaclass, and I list the attributes as normal attrbutes, because the metaclass will convert them into properties. Why does following the line (in #3) not convert the normal attribute into a property? setattr(cls, attr, property(lambda self: obj)) # incorrect! # 1------------------------------------------------- # nice, but I want the constants to be read-only from types import SimpleNamespace const = SimpleNamespace(YES=1, NO=0, DUNNO=9) const.YES = 0 print(const) # 2------------------------------------------------- # works, but I wonder if there's a builtin way class Const(object): """Adding attributes is ok, modifying them is not""" YES = property(lambda self: 1) NO = property(lambda self: 0) DUNNO = property(lambda self: 42) #THROWS_ERROR = 666 def __new__(cls): for attr in dir(cls): if attr.startswith('_'): continue elif not isinstance(getattr(cls, attr), property): raise ValueError("Only properties allowed") return super().__new__(cls) def __repr__(self): kv = ["%s=%s" % (attr, getattr(self, attr)) for \ attr in sorted(dir(Const)) if not attr.startswith('_')] return "ReadOnlyNamespace(" + ", ".join(kv) + ")" c = Const() print(repr(c)) #c.YES = 42 # raises AttributeError (desired behavior) print(c.YES) # 3------------------------------------------------- class Meta(type): def __new__(cls, name, bases, attrs): for attr, obj in attrs.items(): if attr.startswith('_'): continue elif not isinstance(obj, property): import pdb;pdb.set_trace() #setattr(cls, attr, property(lambda self: obj)) # incorrect! raise ValueError("Only properties allowed") return super().__new__(cls, name, bases, attrs) class MyReadOnlyConst(metaclass=Meta): __metaclass__ = Meta YES = property(lambda self: 1) NO = property(lambda self: 0) DUNNO = property(lambda self: 42) THROWS_ERROR = 666 c2 = MyReadOnlyConst() print(c2.THROWS_ERROR) #c2.THROWS_ERROR = 777 #print(c2.THROWS_ERROR) Thank you in advance and sorry about the large amount of code! Albert-Jan _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor