Skip to content

Commit

Permalink
Refactor class creation (#272)
Browse files Browse the repository at this point in the history
Instead of adding and possibly later deleting attributes, the class creation is delegated into a cleaner building pattern.
  • Loading branch information
hynek authored Oct 26, 2017
1 parent 5c5677b commit 3040bda
Show file tree
Hide file tree
Showing 15 changed files with 568 additions and 195 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ Changes:
^^^^^^^^

- ``__slots__`` have arrived!
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``.
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``.
`#35 <https://github.com/python-attrs/attrs/issues/35>`_
- Allow the case of initializing attributes that are set to ``init=False``.
This allows for clean initializer parameter lists while being able to initialize attributes to default values.
Expand Down
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ Testimonials

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

.. -end-
.. -project-information-
Getting Help
============
Expand All @@ -105,9 +108,6 @@ Please use the ``python-attrs`` tag on `StackOverflow <https://stackoverflow.com

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

.. -end-
.. -project-information-

Project Information
===================
Expand Down
1 change: 1 addition & 0 deletions changelog.d/269.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.
1 change: 1 addition & 0 deletions changelog.d/270.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.
1 change: 1 addition & 0 deletions changelog.d/272.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.
5 changes: 4 additions & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ class C(object):

collect_ignore = []
if sys.version_info[:2] < (3, 6):
collect_ignore.append("tests/test_annotations.py")
collect_ignore.extend([
"tests/test_annotations.py",
"tests/test_init_subclass.py",
])
6 changes: 4 additions & 2 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ By default, instances of classes have a dictionary for attribute storage.
This wastes space for objects having very few data attributes.
The space consumption can become significant when creating large numbers of instances.

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__``.
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__``.
For ``attrs`` classes it's enough to set ``slots=True``:

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

- 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.
- 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.
In almost all cases this isn't a problem, but we mention it for the sake of completeness.

* One notable problem is that certain metaclass features like ``__init_subclass__`` do not work with slot classes.

- Using :mod:`pickle` with slot classes requires pickle protocol 2 or greater.
Python 2 uses protocol 0 by default so the protocol needs to be specified.
Python 3 uses protocol 3 by default.
Expand Down
6 changes: 4 additions & 2 deletions docs/how-does-it-work.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ In order to ensure that sub-classing works as you'd expect it to work, ``attrs``
Please note that ``attrs`` does *not* call ``super()`` *ever*.
It will write dunder methods to work on *all* of those attributes which also has performance benefits due to fewer function calls.

Once ``attrs`` knows what attributes it has to work on, it writes the requested dunder methods and attaches them to your class.
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``).
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.

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:

.. doctest::

>>> import attr, inspect
>>> @attr.s
... class C:
... class C(object):
... x = attr.ib()
>>> print(inspect.getsource(C.__init__))
def __init__(self, x):
Expand Down
Loading

0 comments on commit 3040bda

Please sign in to comment.