Skip to content

Commit c1c24cc

Browse files
committed
Convert glossary.rst to md
1 parent 9fd0f82 commit c1c24cc

File tree

2 files changed

+106
-104
lines changed

2 files changed

+106
-104
lines changed

docs/glossary.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Glossary
2+
3+
:::{glossary}
4+
dunder methods
5+
"Dunder" is a contraction of "double underscore".
6+
7+
It's methods like `__init__` or `__eq__` that are sometimes also called *magic methods* or it's said that they implement an *object protocol*.
8+
9+
In spoken form, you'd call `__init__` just "dunder init".
10+
11+
Its first documented use is a [mailing list posting](https://mail.python.org/pipermail/python-list/2002-September/155836.html) by Mark Jackson from 2002.
12+
13+
dict classes
14+
A regular class whose attributes are stored in the {attr}`object.__dict__` attribute of every single instance.
15+
This is quite wasteful especially for objects with very few data attributes and the space consumption can become significant when creating large numbers of instances.
16+
17+
This is the type of class you get by default both with and without *attrs* (except with the next APIs {func}`attrs.define()`, [`attrs.mutable()`](attrs.mutable), and [`attrs.frozen()`](attrs.frozen)).
18+
19+
slotted classes
20+
A class whose instances have no {attr}`object.__dict__` attribute and [define](https://docs.python.org/3/reference/datamodel.html#slots) their attributes in a `object.__slots__` attribute instead.
21+
In *attrs*, they are created by passing `slots=True` to `@attr.s` (and are on by default in {func}`attrs.define()`, [`attrs.mutable()`](attrs.mutable), and [`attrs.frozen()`](attrs.frozen)).
22+
23+
Their main advantage is that they use less memory on CPython[^pypy] and are slightly faster.
24+
25+
However, they also come with several possibly surprising gotchas:
26+
27+
- Slotted classes don't allow for any other attribute to be set except for those defined in one of the class' hierarchies `__slots__`:
28+
29+
```{eval-rst}
30+
.. doctest::
31+
32+
>>> from attr import define
33+
>>> @define
34+
... class Coordinates:
35+
... x: int
36+
... y: int
37+
...
38+
>>> c = Coordinates(x=1, y=2)
39+
>>> c.z = 3
40+
Traceback (most recent call last):
41+
...
42+
AttributeError: 'Coordinates' object has no attribute 'z'
43+
```
44+
45+
- Slotted classes can inherit from other classes just like non-slotted classes, but some of the benefits of slotted classes are lost if you do that.
46+
If you must inherit from other classes, try to inherit only from other slotted classes.
47+
48+
- However, [it's not possible](https://docs.python.org/3/reference/datamodel.html#notes-on-using-slots) to inherit from more than one class that has attributes in `__slots__` (you will get an `TypeError: multiple bases have instance lay-out conflict`).
49+
50+
- It's not possible to monkeypatch methods on slotted classes.
51+
This can feel limiting in test code, however the need to monkeypatch your own classes is usually a design smell.
52+
53+
If you really need to monkeypatch an instance in your tests, but don't want to give up on the advantages of slotted classes in production code, you can always subclass a slotted class as a dict class with no further changes and all the limitations go away:
54+
55+
```{doctest}
56+
>>> import unittest.mock
57+
>>> @define
58+
... class Slotted:
59+
... x: int
60+
...
61+
... def method(self):
62+
... return self.x
63+
>>> s = Slotted(42)
64+
>>> s.method()
65+
42
66+
>>> with unittest.mock.patch.object(s, "method", return_value=23):
67+
... pass
68+
Traceback (most recent call last):
69+
...
70+
AttributeError: 'Slotted' object attribute 'method' is read-only
71+
>>> @define(slots=False)
72+
... class Dicted(Slotted):
73+
... pass
74+
>>> d = Dicted(42)
75+
>>> d.method()
76+
42
77+
>>> with unittest.mock.patch.object(d, "method", return_value=23):
78+
... assert 23 == d.method()
79+
```
80+
81+
- Slotted classes must implement {meth}`__getstate__ <object.__getstate__>` and {meth}`__setstate__ <object.__setstate__>` to be serializable with {mod}`pickle` protocol 0 and 1.
82+
Therefore, *attrs* creates these methods automatically for slotted classes.
83+
84+
:::{note}
85+
When decorating with `@attr.s(slots=True)` and the class already implements the {meth}`__getstate__ <object.__getstate__>` and {meth}`__setstate__ <object.__setstate__>` methods, they will be *overwritten* by *attrs* autogenerated implementation by default.
86+
87+
This can be avoided by setting `@attr.s(getstate_setstate=False)` or by setting `@attr.s(auto_detect=True)`.
88+
89+
{func}`~attrs.define` sets `auto_detect=True` by default.
90+
:::
91+
92+
Also, [think twice](https://www.youtube.com/watch?v=7KnfGDajDQw) before using {mod}`pickle`.
93+
94+
- Slotted classes are weak-referenceable by default.
95+
This can be disabled in CPython by passing `weakref_slot=False` to `@attr.s` [^pypyweakref].
96+
97+
- Since it's currently impossible to make a class slotted after it's been created, *attrs* has to replace your class with a new one.
98+
While it tries to do that as graciously as possible, certain metaclass features like {meth}`object.__init_subclass__` do not work with slotted classes.
99+
100+
- The {attr}`class.__subclasses__` attribute needs a garbage collection run (which can be manually triggered using {func}`gc.collect`), for the original class to be removed.
101+
See issue [#407](https://github.com/python-attrs/attrs/issues/407) for more details.
102+
:::
103+
104+
[^pypy]: On PyPy, there is no memory advantage in using slotted classes.
105+
106+
[^pypyweakref]: On PyPy, slotted classes are naturally weak-referenceable so `weakref_slot=False` has no effect.

docs/glossary.rst

Lines changed: 0 additions & 104 deletions
This file was deleted.

0 commit comments

Comments
 (0)