5
class B(type):
    __slots__ = ()

class A(metaclass=B):
    pass

A.test = "test"

"A" is instance of metaclass "B" and "B" have __slots__ defined - why I have __dict__ at class A? How I can create class object without __dict__?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Damamaty
  • 65
  • 5
  • http://stackoverflow.com/questions/4877290/what-is-the-dict-dict-attribute-of-a-python-class – tyteen4a03 Aug 09 '14 at 17:39
  • Why do you want a class with no `__dict__`? Maybe there is a way to solve the problem differently. – Ned Batchelder Aug 09 '14 at 19:45
  • @NedBatchelder: Yes, I want a class with no \__dict__. Its strange that \__slots__ works in class<->instance and doesn't with metaclass<->class. I was thinking that built-in classes have no \__dict__, but apparently it's just not showing in dir(). E.g. hasattr(int, '\__dict__') == True – Damamaty Aug 09 '14 at 23:33
  • @Damamat: you haven't said *why* you want a class with no `__dict__`. What's bad about having a dict? Can you explain? – Ned Batchelder Aug 10 '14 at 02:59
  • Purely academic interest. – Damamaty Aug 10 '14 at 12:26

2 Answers2

4

You cannot do this; classes always have a __dict__.

You can only use __slots__ on classes to produce instances without a __dict__, not on meta types. You'd normally only produce a few classes, so there is not much point in supporting __slots__ on metaclasses.

Don't use __slots__ to prevent attributes being set. Use __setattr__ for that instead:

class NoAttributesClassMeta(type):
    def __setattr__(cls, name, value):
        if name not in cls.__dict__:
            raise AttributeError("Cannot set attributes")
        type.__setattr__(cls, name, value)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • So there's no way to define a metaclass whose instances have `__slots__` defined (so _their_ instances won't have a `__dict__`)? This is what I think the OP is trying to accomplish. – martineau Aug 09 '14 at 18:00
  • @martineau: I don't think so; why the test for `A.test = 'test'` then? – Martijn Pieters Aug 09 '14 at 18:03
  • Oops, you're right about what the OP asked -- I was misunderstanding the question. +1 – martineau Aug 09 '14 at 18:14
2

__slots__ won't stop you from setting an attribute to a class, you need to override __setattr__ for that. Something like this should do it:

class B(type):
    def __new__(cls, clsname, bases, dct):
        dct['__slots__']  = ('x',)
        return type.__new__(cls, clsname, bases, dct)
    def __setattr__(cls, attr, val):
        if attr not in cls.__slots__:
            raise AttributeError('Can\'t set {!r}'.format(attr))
        else:
            type.__setattr__(cls, attr, val)

class A(metaclass=B):
    pass

Demo:

>>> A.x = 1
>>> A.y = 2
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    A.y = 2
  File "C:\Python27\so.py", line 7, in __setattr__
    raise AttributeError('Can\'t set {!r}'.format(attr))
AttributeError: Can't set 'y'
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504