简体   繁体   中英

If an object doesn't have `__dict__`, must its class have a `__slots__` attribute?

From https://stackoverflow.com/a/1529099/156458

To support arbitrary attribute assignment, an object needs a __dict__ : a dict associated with the object, where arbitrary attributes can be stored. Otherwise, there's nowhere to put new attributes.

An instance of object does not carry around a __dict__ -- if it did, before the horrible circular dependence problem (since __dict__ , like most everything else, inherits from object ;-), this would saddle every object in Python with a dict, which would mean an overhead of many bytes per object that currently doesn't have or need a dict (essentially, all objects that don't have arbitrarily assignable attributes don't have or need a dict).

...

When the class has the __slots__ special attribute (a sequence of strings), then the class statement (more precisely, the default metaclass, type ) does not equip every instance of that class with a __dict__ (and therefore the ability to have arbitrary attributes), just a finite, rigid set of "slots" (basically places which can each hold one reference to some object) with the given names.

If an object doesn't have __dict__ , must its class have a __slots__ attribute?

For example, an instance of object doesn't have a __dict__ :

>>> object().__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute '__dict__'

but it doesn't have __slots__ either:

>>> object.__slots__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'object' has no attribute '__slots__'

Do object instances have any attributes at all?

How many possibilities are there:

  • an object has __dict__ , and its class has __dict__ but no __slots__
  • an object doesn't have __dict__ , and its class has __slots__
  • an object doesn't have __dict__ , and its class doesn't have __slots__ ?

Is it possible to tell if an object has __dict__ from its class?

  • if its class has __slots__ , then it doesn't have __dict__ , correct?

  • if its class doesn't have __slots__ , how can I tell if it has __dict__ or not?

For user defined classes (defined using the class keyword in regular Python code), a class will always have __slots__ on the class, __dict__ on the instance, or both (if one of the slots defined is '__dict__' , or one of the user defined classes in an inheritance chain defines __slots__ and another one does not, creating __dict__ implicitly). So that's three of four possibilities covered for user defined classes.

Edit: A correction: Technically, a user-defined class could have neither ; the class would be defined with __slots__ , but have it deleted after definition time (the machinery that sets up the type doesn't require __slots__ to persist after the class definition finishes). No sane person should do this, and it could have undesirable side-effects (full behavior untested), but it's possible.

For built-in types, at least in the CPython reference interpreter, they're extremely unlikely to have __slots__ (if they did, it would be to simulate a user-defined class, defining it doesn't actually do anything useful). A built-in type typically stores its attributes as raw C level values and pointers on a C level struct, optionally with explicitly created descriptors or accessor methods, which eliminates the purpose of __slots__ , which are just a convenient limited purpose equivalent of such struct games for user defined classes. __dict__ is opt-in for built-in types, not on by default (though the opt-in process is fairly easy; you need to put a PyObject* entry somewhere in the struct and provide the offset to it in the type definition).

To be clear, __dict__ need not appear on the class for it to appear on its instances ; __slots__ is class level, and can suppress the __dict__ on the instance , but has no effect on whether the class itself has a __dict__ ; user defined classes always have __dict__ , but their instances won't if you're careful to use __slots__ appropriately.

So in short:

(Sane) User defined classes have at least one of __dict__ (on the instances) or __slots__ (on the class), and can have both. Insane user defined classes could have neither, but only a deranged developer would do it.

Built-in classes often have neither, may provide __dict__ , and almost never provide __slots__ as it is pointless for them.

Examples:

# Class has __slots__, instances don't have __dict__
class DictLess:
    __slots__ = ()

# Instances have __dict__, class lacks __slots__
class DictOnly:
    pass

# Class has __slots__, instances have __dict__ because __slots__ declares it
class SlottedDict:
    __slots__ = '__dict__',

# Class has __slots__ without __dict__ slot, instances have it anyway from unslotted parent
class DictFromParent(DictOnly):
    __slots__ = ()

# Complete insanity: __slots__ takes effect at class definition time, but can
# be deleted later, without changing the class behavior:
class NoSlotNoDict:
    __slots__ = ()
del NoSlotNoDict.__slots__
# Instances have no __dict__, class has no __slots__ but acts like it does
# (the machinery to make it slotted isn't undone by deleting __slots__)
# Please, please don't actually do this

# Built-in type without instance __dict__ or class defined __slots__:
int().__dict__  # Raises AttributeError
int.__slots__   # Also raises AttributeError

# Built-in type that opts in to __dict__ on instances:
import functools
functools.partial(int).__dict__ # Works fine
functools.partial.__slots__ # Raises AttributeError

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM