[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)