103 lines
2.9 KiB
ReStructuredText
103 lines
2.9 KiB
ReStructuredText
.. _examples:
|
|
|
|
Examples
|
|
========
|
|
|
|
The simplest possible usage would be:
|
|
|
|
.. doctest::
|
|
|
|
>>> import attr
|
|
>>> @attr.s
|
|
... class Empty(object):
|
|
... pass
|
|
>>> Empty()
|
|
Empty()
|
|
>>> Empty() == Empty()
|
|
True
|
|
>>> Empty() is Empty()
|
|
False
|
|
|
|
So in other words: ``attrs`` useful even without actual attributes!
|
|
|
|
But you'll usually want some data on your classes, so let's add some:
|
|
|
|
.. doctest::
|
|
|
|
>>> @attr.s
|
|
... class Coordinates(object):
|
|
... x = attr.ib()
|
|
... y = attr.ib()
|
|
|
|
These by default, all features are added, so you have immediately a fully functional data class with a nice ``repr`` string and comparison methods.
|
|
|
|
.. doctest::
|
|
|
|
>>> c1 = Coordinates(1, 2)
|
|
>>> c1
|
|
Coordinates(x=1, y=2)
|
|
>>> c2 = Coordinates(x=2, y=1)
|
|
>>> c2
|
|
Coordinates(x=2, y=1)
|
|
>>> c1 == c2
|
|
False
|
|
|
|
As shown, the generated ``__init__`` method allows both for positional and keyword arguments.
|
|
|
|
If playful naming turns you off, ``attrs`` comes with no-nonsense aliases:
|
|
|
|
.. doctest::
|
|
|
|
>>> @attr.attributes
|
|
... class SeriousCoordinates(object):
|
|
... x = attr.attr()
|
|
... y = attr.attr()
|
|
>>> SeriousCoordinates(1, 2)
|
|
SeriousCoordinates(x=1, y=2)
|
|
>>> attr.ls(Coordinates) == attr.ls(SeriousCoordinates)
|
|
True
|
|
|
|
|
|
Sometimes you want to have default values for your initializer.
|
|
And sometimes you even want mutable objects as default values (ever used accidentally ``def f(arg=[])``?).
|
|
``attrs`` has you covered in both cases:
|
|
|
|
.. doctest::
|
|
|
|
>>> import collections
|
|
>>> @attr.s
|
|
... class Connection(object):
|
|
... socket = attr.ib()
|
|
... @classmethod
|
|
... def connect(cl, db_string):
|
|
... # connect somehow to db_string
|
|
... return cl(socket=42)
|
|
>>> @attr.s
|
|
... class ConnectionPool(object):
|
|
... db_string = attr.ib()
|
|
... pool = attr.ib(default_factory=collections.deque)
|
|
... debug = attr.ib(default_value=False)
|
|
... def get_connection(self):
|
|
... try:
|
|
... return self.pool.pop()
|
|
... except IndexError:
|
|
... if self.debug:
|
|
... print "New connection!"
|
|
... return Connection.connect(self.db_string)
|
|
... def free_connection(self, conn):
|
|
... if self.debug:
|
|
... print "Connection returned!"
|
|
... self.pool.appendleft(conn)
|
|
...
|
|
>>> cp = ConnectionPool("postgres://localhost")
|
|
>>> cp
|
|
ConnectionPool(db_string='postgres://localhost', pool=deque([]), debug=False)
|
|
>>> conn = cp.get_connection()
|
|
>>> conn
|
|
Connection(socket=42)
|
|
>>> cp.free_connection(conn)
|
|
>>> cp
|
|
ConnectionPool(db_string='postgres://localhost', pool=deque([Connection(socket=42)]), debug=False)
|
|
|
|
More information on why class methods for constructing objects are awesome can be found in this insightful `blog post <http://as.ynchrono.us/2014/12/asynchronous-object-initialization.html>`_.
|