Question: One use of __slots__ in Python is to disallow new attributes: class Thing: __slots__ = 'a', 'b' thing = Thing() thing.c = 'hello' # error  However, this doesn’t work if a class inherits from another slotless class: class Whatever: pass class Thing(Whatever): __slots__ = 'a', 'b' thing = Thing() thing.c = 'hello' # ok  That’s because it also inherits the __dict__ from its parent which allows additional attributes. Is there any way of blocking the __dict__ from being inherited? It seems to me that this would allow a sub class to be less generic that its parent, so it’s surprising that it doesn’t work this way naturally. Comment OK, the question arises as whether this would violate the https://en.wikipedia.org/wiki/Liskov_substitution_principle . This, in turn buys into a bigger discussion on inheritance. Most books would, for example, suggest that a circle is an ellipse so a Circle class should inherit from an Ellipse class. However, since a circle is more restrictive, this would violate the Liskov Substitution Principle in that a sub class should not do less than the parent class. In this case, I’m not sure about whether it applies here. Python has no access modifiers, so object data is already over-exposed. Further, without __slots__ Python objects are pretty promiscuous about adding additional attributes, and I’m not sure that’s really part of the intended discussion.

Answer: If you are willing to use a metaclass, you can prevent this. Simply insert an empty sequence for '__slots__' in the namespace returned by __prepare__ this is a hook that prepares the namespace that will be used for the class, it defaults to a normal dict(), and we can just force the subclass to have an empty (not unspecified) __slots__ class EmptySlotsMeta(type): @classmethod def __prepare__(metacls, name, bases): return {"__slots__":()} class Foo(metaclass=EmptySlotsMeta): __slots__ = 'x', 'y' def __init__(self, x=0, y=0): self.x = x self.y = y class Bar(Foo): pass class Baz(Foo): __slots__ = ('z',) def __init__(self, x=0, y=0, z=0): super().__init__(x, y) self.z = z  Now, in a REPL: >>> foo = Foo() >>> bar = Bar() >>> baz = Baz() >>> foo.z = 99 Traceback (most recent call last): File "<python-input-25>", line 1, in <module> foo.z = 99 ^^^^^ AttributeError: 'Foo' object has no attribute 'z' and no __dict__ for setting new attributes >>> bar.z = 99 Traceback (most recent call last): File "<python-input-26>", line 1, in <module> bar.z = 99 ^^^^^ AttributeError: 'Bar' object has no attribute 'z' and no __dict__ for setting new attributes >>> baz.z = 99  Note, a class with this metaclass can still define their own __slots__ (as in Foo or its second subclass Baz above). That's probably desirable. As with most things in Python, you can put some guardrails around it but it isn't worth trying to make it bulletproof. Note, although it is commonly used this way, __slots__ were not added for this use-case, that is, to restrict attributes. It exists mainly as a memory optimization, since a standard instance carries around a whole dict object. Edit: I undeleted this on the OP's request, but I'm still not sure it answers the exact question, note: class Whatever: pass class Foo(Whatever, metaclass=EmptySlotsMeta): __slots__ = ('x','y') Foo().z = 1 # totally works  But it has to work this way, because the superclass will almost certainly create attributes, and it needs a __dict__ to do that unless it had defined slots.