Skip to content

Commit 3040bda

Browse files
authored
Refactor class creation (#272)
Instead of adding and possibly later deleting attributes, the class creation is delegated into a cleaner building pattern.
1 parent 5c5677b commit 3040bda

15 files changed

Lines changed: 568 additions & 195 deletions

CHANGELOG.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ Changes:
230230
^^^^^^^^
231231

232232
- ``__slots__`` have arrived!
233-
Classes now can automatically be `slots <https://docs.python.org/3.5/reference/datamodel.html#slots>`_-style (and save your precious memory) just by passing ``slots=True``.
233+
Classes now can automatically be `slots <https://docs.python.org/3/reference/datamodel.html#slots>`_-style (and save your precious memory) just by passing ``slots=True``.
234234
`#35 <https://github.com/python-attrs/attrs/issues/35>`_
235235
- Allow the case of initializing attributes that are set to ``init=False``.
236236
This allows for clean initializer parameter lists while being able to initialize attributes to default values.

README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ Testimonials
9797

9898
-- **Kenneth Reitz**, author of `requests <http://www.python-requests.org/>`_, Python Overlord at Heroku, `on paper no less <https://twitter.com/hynek/status/866817877650751488>`_
9999

100+
.. -end-
101+
102+
.. -project-information-
100103
101104
Getting Help
102105
============
@@ -105,9 +108,6 @@ Please use the ``python-attrs`` tag on `StackOverflow <https://stackoverflow.com
105108

106109
Answering questions of your fellow developers is also great way to help the project!
107110

108-
.. -end-
109-
110-
.. -project-information-
111111

112112
Project Information
113113
===================

changelog.d/269.change.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.

changelog.d/270.change.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.

changelog.d/272.change.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.

conftest.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,7 @@ class C(object):
2121

2222
collect_ignore = []
2323
if sys.version_info[:2] < (3, 6):
24-
collect_ignore.append("tests/test_annotations.py")
24+
collect_ignore.extend([
25+
"tests/test_annotations.py",
26+
"tests/test_init_subclass.py",
27+
])

docs/examples.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ By default, instances of classes have a dictionary for attribute storage.
470470
This wastes space for objects having very few data attributes.
471471
The space consumption can become significant when creating large numbers of instances.
472472

473-
Normal Python classes can avoid using a separate dictionary for each instance of a class by `defining <https://docs.python.org/3.5/reference/datamodel.html#slots>`_ ``__slots__``.
473+
Normal Python classes can avoid using a separate dictionary for each instance of a class by `defining <https://docs.python.org/3/reference/datamodel.html#slots>`_ ``__slots__``.
474474
For ``attrs`` classes it's enough to set ``slots=True``:
475475

476476
.. doctest::
@@ -505,9 +505,11 @@ Slot classes are a little different than ordinary, dictionary-backed classes:
505505
...
506506
AttributeError: 'Coordinates' object has no attribute 'z'
507507

508-
- Since non-slot classes cannot be turned into slot classes after they have been created, ``attr.s(.., slots=True)`` will *replace* the class it is applied to with a copy.
508+
- Since non-slot classes cannot be turned into slot classes after they have been created, ``attr.s(slots=True)`` will *replace* the class it is applied to with a copy.
509509
In almost all cases this isn't a problem, but we mention it for the sake of completeness.
510510

511+
* One notable problem is that certain metaclass features like ``__init_subclass__`` do not work with slot classes.
512+
511513
- Using :mod:`pickle` with slot classes requires pickle protocol 2 or greater.
512514
Python 2 uses protocol 0 by default so the protocol needs to be specified.
513515
Python 3 uses protocol 3 by default.

docs/how-does-it-work.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ In order to ensure that sub-classing works as you'd expect it to work, ``attrs``
1717
Please note that ``attrs`` does *not* call ``super()`` *ever*.
1818
It will write dunder methods to work on *all* of those attributes which also has performance benefits due to fewer function calls.
1919

20-
Once ``attrs`` knows what attributes it has to work on, it writes the requested dunder methods and attaches them to your class.
20+
Once ``attrs`` knows what attributes it has to work on, it writes the requested dunder methods and -- depending on whether you wish to have ``__slots__`` -- creates a new class for you (``slots=True``) or attaches them to the original class (``slots=False``).
21+
While creating new classes is more elegant, we've run into several edge cases surrounding metaclasses that make it impossible to go this route unconditionally.
22+
2123
To be very clear: if you define a class with a single attribute without a default value, the generated ``__init__`` will look *exactly* how you'd expect:
2224

2325
.. doctest::
2426

2527
>>> import attr, inspect
2628
>>> @attr.s
27-
... class C:
29+
... class C(object):
2830
... x = attr.ib()
2931
>>> print(inspect.getsource(C.__init__))
3032
def __init__(self, x):

0 commit comments

Comments
 (0)