One of the prime uses of a dataclass is to be a mutable namedtuple. And the syntax can be almost identical:
Part = make_dataclass('Part', ['part_num', 'description', 'quantity'])
(from Raymond Hettinger's twitter)This has the added benefit of not requiring type hinting, if you don't want to bother with such things.
(attrs) % ipython
Python 2.7.14 (default, Oct 19 2017, 23:28:49)
Type "copyright", "credits" or "license" for more information.
IPython 5.6.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: import attr
In [2]: Part = attr.make_class("Part", ["part_num", "description", "quantity"])
In [3]: Part?
Init signature: Part(self, part_num, description, quantity)
Docstring: <no docstring>
Type: type
Outside of the name of the thing that creates the item, the syntax is identical to what you have here.edit: removed triple backticks, indented with 2sp according to https://news.ycombinator.com/formatdoc rules
It cuts down on the per-instance memory overhead, for cases where you're creating a ton of these objects. It can be useful even when not memory-constrained, because it will throw AttributeError, rather than succeeding silently, if you make a typo when assigning to an object attribute.
0: https://www.python.org/dev/peps/pep-0557/#support-for-automa...
import resource
import sys
class WithoutSlots:
def __init__(self, a, b):
self.a = a
self.b = b
class WithSlots:
__slots__ = ('a', 'b')
def __init__(self, a, b):
self.a = a
self.b = b
resource.setrlimit(resource.RLIMIT_AS, (1024 ** 3, 1024 ** 3))
cls = WithSlots if sys.argv[1:] == ['slots'] else WithoutSlots
count, instances = 0, []
while True:
try:
instances.append(cls(1, 2))
except MemoryError:
break
count = len(instances)
del instances
print(cls, count)
Here are numbers from my laptop: $ python3.6 /tmp/slots.py
<class '__main__.WithoutSlots'> 5830382
$ python3.6 /tmp/slots.py slots
<class '__main__.WithSlots'> 16081964
That's almost 3x more instances with __slots__! This isn't the case with PyPy, though, thanks to a more efficient representation of objects:https://morepypy.blogspot.com/2010/11/efficiently-implementi...
My point was not that __slots__ does nothing, but that there are more important things to worry about.
I claim that in this case, __slots__ is exactly the right thing to worry about.
BTW, have you considered using the complex type to handle that for you? It's 2d and ints should be safe in float representation. If it overflows it'll crash nicely.
One thing the stdlib implementation has going for it: better naming. attr.ib() is not exactly crystal-clear.