[HN Gopher] Attrs - The One Python Library Everyone Needs
___________________________________________________________________
Attrs - The One Python Library Everyone Needs
Author : aqeelat
Score : 53 points
Date : 2021-12-24 20:07 UTC (2 hours ago)
(HTM) web link (glyph.twistedmatrix.com)
(TXT) w3m dump (glyph.twistedmatrix.com)
| skrtskrt wrote:
| IMO Pydantic is way more ergonomic, has great defaults, and
| easier to bend to your will when you want to use it a little
| differently.
|
| Lots of love to Attrs, which is a great library and is a
| component of a lot of great software. It was my go-to library for
| years before Pydantic matured, but I think a lot of people have
| rightly started to move on to Pydantic, particularly with the
| popularity of FastAPI
| ledauphin wrote:
| I'd say the opposite. Specifically, Pydantic tries to do
| everything, and as a result (partly b/c they favor base classes
| over higher order functions), it isn't as composable as attrs
| is.
|
| I've done some truly amazing things with attrs because of that
| composability. If I'd wanted the same things with Pydantic, it
| would have had to be a feature request.
| sterlinm wrote:
| I think this was on HN at some point, but this article makes
| the case for why/when you'd want to use attrs rather than
| pydantic. https://threeofwands.com/why-i-use-attrs-instead-of-
| pydantic...
| kaashif wrote:
| Pydantic is dataclasses, except types are validated at runtime?
| It's nice and looks just like a normal dataclass looking at
| https://pydantic-docs.helpmanual.io/
|
| For any larger program, pervasive type annotations and
| "compile" time checking with mypy is a really good idea though,
| which somewhat lessens the need for runtime checking.
| skrtskrt wrote:
| Pydantic types will be checked by mypy or any other static
| type analysis tool as well.
|
| I don't expect any type-related thing to be remotely safe in
| Python without applying at least mypy and pylint, potentially
| pyright as well, plus, as always with an interpreted
| language, unit tests for typing issues that would be caught
| by a compiler in another language
| jhardy54 wrote:
| Pydantic works with mypy, so you have validation at build-
| time and parsing at runtime.
| joshuamorton wrote:
| Pydantic is useful if you're dealing with parsing unstructured
| (or sort of weakly untrusted) data. If you just want "things
| that feel like structs", dataclassess or attrs are going to be
| just as easy and more performant (and due to using decorators
| and not metaclasses, more capable of playing nicely with other
| things).
| ahurmazda wrote:
| Do you have concern with speed or memory footprint of pydantic
| compared to the rest (attrs, dataclasses etc)? Pydantic seems
| insistent on parsing/validating the types at runtime (which
| makes good sense for something like FastAPI).
| skrtskrt wrote:
| We always used attrs with the runtime type validators anyway.
| Getting those types checked in Python was way more valuable
| to my teams than the minor boilerplate reduction.
|
| If you're worried about the performance hit of extra crap
| happening at runtime... dear lord use another programming
| language.
|
| Dataclasses is just... meh. Pydantic and Attrs just have so
| many great features, I would never use dataclasses unless
| someone had a gun to my head to only use the standard
| library. I don't know of a single Python project that uses
| dataclasses where Pydantic or Attrs would do (I'm sure they
| exist, but I've never run across it).
|
| Dataclasses honestly seems very reactionary by the Python
| devs, since Attrs was getting so popular and used
| _everywhere_ that it got a little embarrassing for Python
| that something so obviously needed in the language just
| wasn't there. Those that weren't using Attrs runtime
| validators often did something similar to Attrs by abusing
| NamedTuple with type hints. There were tons of "why isnt
| Attrs in the stdlib" comments, which is an annoying type of
| comment to make, but it happens. So they added dataclasses,
| but having all the many features that Attrs has isn't a very
| standard-library-like approach, so we got... dataclasses.
| Like "look, it's what you wanted, right!?". Well no not
| really, thanks we'll just keep using Attrs and then Pydantic
| ahurmazda wrote:
| Thanks. You do make a lot of good points.
|
| Attrs just has the features I need for now. It certainly
| feel a touch verbose but I'm happy to pay the price.
| ledauphin wrote:
| can you tell me which parts feel verbose? In my recent
| usage, I've not found myself using the older, more
| verbose approaches.
| atorodius wrote:
| This is only remotely relevant but I recently learned that the
| related `dataclasses` id implemented by constructing _string
| representations_ of functions and calling `exec` on them.
|
| https://github.com/python/cpython/blob/3.10/Lib/dataclasses....
|
| Kind of blew my mind
| gjvc wrote:
| see also "dataclasses" since python 3.7
| samplenoise wrote:
| Raymond Hettinger's (perhaps biased) take on dataclasses vs
| attrs:
|
| https://m.youtube.com/watch?v=T-TwcmT6Rcw
| falafelite wrote:
| Came here to say this, dataclasses have been super helpful for
| a big part of the pain point highlighted by the author. More
| often than not, that is enough for me.
| selimnairb wrote:
| Yes. There needs to be a very good reason for me to pull in a
| third party library (in this day and age, given supply chain
| attacks, etc.). I don't see what Attrs gives me that
| dataclasses does not.
| 4ec0755f5522 wrote:
| Python's STL is such that using it is a code smell. It's
| better to just use the right tool for the job: you are
| almost guaranteed to need at least one external
| library/module for any project of even moderate complexity.
| So bite the bullet, invest in the time/tooling to do
| packaging correctly, and use the very excellent Python
| ecosystem (isn't it why you are using Python to begin
| with?) that you have at your disposal.
|
| Sticking with the "rusty, leaking batteries included!" in
| the STL is a bad call and I don't believe it is safe,
| either; most of the STL is abandonware that is just being
| shipped for backward compatibility sake. Don't make future
| product decisions, design decisions etc. based on Python
| teams' deprecation requirements!
|
| I've been writing Python a long time and have grown quite
| frustrated by some of its warts. But every time I look at
| seriously investing in another language attrs is one of the
| few things I wouldn't want to give up. It's not perfect but
| I'll take very, very good when I can get it, yeah?
| nsonha wrote:
| Not a python guy, so confused as to why a thing called
| namedtuple behaves like dataclasses, what are their different
| usecases?
| jeeeb wrote:
| From a users perspective data classes look kind of like a C
| struct and in particular include type annotations so fit well
| with type checkers. They also allow for default values and
| give more control over generating equality, hash, string and
| initialisation methods.
|
| Comparatively named tuples are an older language feature
| which essentially allow you to define named accessors for
| tuple elements. IIRC, these days you can also define type
| annotations for them.
|
| Their use case essentially overlap. Personally I much prefer
| data classes.
| rguillebert wrote:
| Namedtuples also behave like tuples, which is great when you
| want to incrementally turn tuples into classes but if you
| want an easy way of creating classes, it's probably not a
| good idea to have them behave like tuples. Plus dataclasses
| have more features.
| aix1 wrote:
| Named tuples have been around for a long time (since 2.6),
| whereas dataclasses are a relatively recent addition to the
| standard library (3.7).
|
| Their differences are highlighted in the dataclasses PEP:
| https://www.python.org/dev/peps/pep-0557/#why-not-just-
| use-n...
| nsonha wrote:
| looks like the key thing is immutability
| aix1 wrote:
| To clarify, both named tuples and dataclasses can be
| immutable (the former are always immutable and the latter
| can be made immutable with `frozen=True`).
|
| There is no way, however, to make a named tuple
| _mutable_.
| ahurmazda wrote:
| dataclasses also have the slots kwargs since 3.10. Should help
| with faster access and memory
| greymalik wrote:
| attrs is a superset of dataclasses.
| nmca wrote:
| counterpoint: stdlib is where things go to die
| danbmil99 wrote:
| Why is Attrs incorrectly capitalized in the headline? Is that an
| automatic feature of the software?
| NeutralForest wrote:
| For anyone interested in differences between attrs and pydantic,
| how to use dataclasses, etc. I can't recommend the mCoding
| channel enough, this video :
| https://www.youtube.com/watch?v=vCLetdhswMg goes into the
| different libraries and there are other videos going more in
| depth on how to use them.
| flohofwoe wrote:
| ...or one could just use Python without classes, just functions.
| TBH I never quite understood why Python has the class keyword,
| it's a much better language without.
| rthomas6 wrote:
| I thought like you for several years. Then one day, I needed a
| custom type. You can use dicts (or lists, or namedtuples, I
| guess?), but it just ends up being cleaner and more idiomatic
| to define a class for the type, because you can define common
| methods for them.
|
| The article mentions quaternions. If you make a quaternion type
| (class), you can define addition, multiplication, comparison,
| etc. for it (methods). If you represent a quaternion any other
| way, you can't say a * b. Or maybe you can, but I don't know
| how.
| ledauphin wrote:
| attrs really isnt about OO-style classes - it's specifically
| meant to provide struct-like declarative data containers, and
| these can help bridge the gap between the toolset that Python
| provides and functional (data-first) programming styles.
| EdSchouten wrote:
| my_point3d = (1.0, 2.5, 7.2)
|
| Voila!
| Fatnino wrote:
| This is explicitly called out in the article.
|
| What does your code do when I try my_point3d.x ?
| zem wrote:
| you can do that with namedtuples too; the problem is that
| tuples are immutable, so you cannot say e.g. `my_point3d.x =
| 10`
| nauticacom wrote:
| I've never understood the appeal of these "define struct-like-
| object" libraries (in any language; I've never understood using
| the standard library's "Struct" in Ruby). My preferred solution
| for addressing complexity is also to decompose the codebase into
| small, understandable, single-purpose objects, but _so few_ of
| them end up being simple value objects like Point3D. Total
| ordering and value equality make sense for value objects but not
| much else, so it really doesn 't improve understandability or
| maintenance that much. And concerns like validation I would never
| want to put in a library for object construction. In web forms
| where there are a limited subset of rules I always want to treat
| the same way, sure, but objects have much more complicated
| relationships with their dependencies that I don't see much value
| in validating them with libraries.
|
| Overall, I really don't see the appeal. It makes the already
| simple cases simpler (was that Point3D implementation _really_
| that bad?) and does nothing for the more complicated cases which
| make up the majority of object relationships.
| [deleted]
| atorodius wrote:
| well one appeal is that you dont have to write constructors,
| that's already enough of a win for me. then you get sane eq,
| and sane str, and already you remove 90% boilerplate
| joshuamorton wrote:
| Ignore all of the validation aspects. In python, you have
| tuples, (x, y, z), then you have namedtuples and then
| attrs/dataclasses/pydantic-style shorthand classes.
|
| These are useful even if only due to the "I can take the three
| related pieces of information I have and stick them next to
| each other". That is, if I have some object I'm modelling and
| it has more than a single attribute (a user with a name and
| age, or an event with a timestamp and message and optional
| error code), I have a nice way to model them.
|
| Then, the important thing is that these are still classes, so
| you can start with @dataclass class
| User: name: str age: int
|
| and have that evolve over time to @dataclass
| class User: name: str age: int
| ... permissions: PermissionSet
| @property def location(): # send
| off an rpc, or query the database for some complex thing.
|
| and since it's still just a class, it'll still work. It
| absolutely makes modelling the more complex cases easier too.
| willseth wrote:
| Someone should tell this person about dataclasses
| geofft wrote:
| dataclasses was explicitly inspired by attrs.
| https://github.com/ericvsmith/dataclasses/issues/1
| shakna wrote:
| Attrs was mentioned in the PEP [0] for dataclasses.
|
| [0] https://www.python.org/dev/peps/pep-0557/#why-not-just-
| use-a...
| 4ec0755f5522 wrote:
| I started a project with dataclasses and quickly ran into their
| limitations (which are by design) and migrated to attrs. It's
| quite a bit better.
|
| If you take 10 seconds to read attrs website they do go over
| the differences and maybe discussing those would be more
| valuable than some cheap snark.
| [deleted]
| nhumrich wrote:
| I mean, the blog post is older than dataclasses
| bjourne wrote:
| Costs: Depending on a relatively unknown library. Using arcane
| class decorators and unusual syntactic constructs: @attr.s and x
| = attr.ib() (a pun?).
|
| Benefits: Saving at best 10-15 lines of boilerplate per data
| class. Much less if namedtuple works for you.
|
| If you want to save lines in __init__ you can write "for k, v in
| locals().items(): setattr(self, k, v)". But you shouldn't.
| ledauphin wrote:
| there are newer (since 2020) syntactic constructs that might be
| more to your liking. take a look at the docs again.
|
| Incidentally, I'd recommend against Named Tuples for non-
| trivial software. Because they can be indexed by integer and
| unpacked like tuples, additions of new fields are backwards-
| incompatible with existing code.
| atorodius wrote:
| yeah this has bitten me before. combine it with overwriting
| len for a namedtuple and you have a proper mess
| unbanned wrote:
| Erm. Pydantic. Or dataclasses.
| jpalomaki wrote:
| This is from 2016.
___________________________________________________________________
(page generated 2021-12-24 23:00 UTC)