""" See the expected/unexpected behaviour at the end of the file. It behaves perfeclty well in python 3.3 See: - Dict access in `MessageMeta`.__new__ - End of the file showing the weird effect Has been tested in: - py 3.2.2 - Failed - py 3.2.3 - Failed - py 3.3.2 - Succeeded """ __supported_types__ = (int, float, bool, str, bytes) type_string = ', '.join([typ.__name__ for typ in __supported_types__]) class Attribute(object): __slots__ = ['_type', '_optional', '_value'] def __init__(self, attr_type, optional=False): if attr_type not in __supported_types__: raise TypeError("Expected any of ({0}) as attr_type. Provided type ({1}) either not " "supported or 'not yet' supported".format(type_string, attr_type.__name__)) self._type = attr_type self._optional = optional self._value = None def __get__(self, ref, owner): return self._value def __set__(self, ref, value): if not isinstance(value, self._type): raise TypeError("Expected type is ({0}), " "instead received ({1})".format(type(value).__name__, self._type.__name__)) else: self._value = value def __delete__(self, ref): raise Exception("You can not remove a messages Attribute, as it is part of the Message" " definition") class MessageMeta(type): def __new__(meta, name, parents, attrs): __metadict__ = {} """ By just commenting out the following lines, that access the dict_proxy to the attrs to become the __dict__, everything works just fine. Python 3.3 works. """ for name, value in attrs.items(): if isinstance(value, Attribute): __metadict__[name] = value attrs['__slots__'] = [] # Ensure all children have a empty def of this attrs['__metadict__'] = __metadict__ return super(MessageMeta, meta).__new__(meta, name, parents, attrs) class Message(object, metaclass=MessageMeta): pass """ Failed test case """ class TestMessage(Message): first_attr = Attribute(int, False) secnond_attr = Attribute(str, True) c = TestMessage() type(c) # 'first_attr' instead of expected 'TestMessage' yet... isinstance(c, Message) # ...True