Live data from Hacker News

Using attrs for everything in Python

glyph.twistedmatrix.com

61–70 of 105 posts

Re: Using attrs for everything in Python

#61
post #16

Earlier quoted context omitted.

Also, read the post and looked over the docs, and don't see any explanation of what `.s` and `.ib` is supposed to mean (though I can figure out from context). Does anyone know what the letters stand for? Struct and instance b…???

attr.s = "attrs" = plural of "attr" attr.ib = "attirb" = alternate spelling of "attr" It's too cute by half.

It's awesome that Glyph wrote this article, but so many people are getting stuck on the default names here (me too, I don't like them so very much) that it's really detracting from the commentariet.

From the Attrs documentation:

(If you don’t like the playful attr.s and attr.ib, you can also use their no-nonsense aliases attr.attributes and attr.attr).

Re: Using attrs for everything in Python

#62
post #11

While the conciseness of attrs is nice, it's not very readable. This: class Point3D(object): def __init__(self, x, y, z): self.x = x self.y = y self.z = z ...is much easier to read than this: import attr @attr.s class Point3D(object): x = attr.ib() y = attr.ib() z = attr.ib() Readability is what I love about Python. I don't think the conciseness of attrs is worth the loss in readability.

According to the article, that's not really a fair comparison. The first example would need functools and at least 3 more methods to get to the same functionality of the latter example, at which point I think the former is less readable. That said, I'm not a big fan of wrapping classes, or this library's weirdly-but-concisely-named functions. I guess I'll have to give this a try the next time I'm writing Python to se…

Those 3 methods aren't at all necessary for most objects you'll create and use.

Re: Using attrs for everything in Python

#63
post #52
post #51

Earlier quoted context omitted.

If the compiler knows a Python array is uniformly of type float, it can, and should, use a dense array of floats to represent it.

Is this safe in all cases? What about complex types? Specifically if you assign a variable to an element in the array, and then replace the element in the array? You'd have to take care not to update the value of the variable.

Assigning a variable to a destination declared to be an incompatible type should produce an error at compile time if possible, and at at run time otherwise. That's what type declarations are all about.

Re: Using attrs for everything in Python

#64
post #52
post #51

Earlier quoted context omitted.

If the compiler knows a Python array is uniformly of type float, it can, and should, use a dense array of floats to represent it.

Is this safe in all cases? What about complex types? Specifically if you assign a variable to an element in the array, and then replace the element in the array? You'd have to take care not to update the value of the variable.

Python's arrays are already typed, and have been for long years. Python's lists may hold arbitrary objects and would be much harder to reason about in this context.

Re: Using attrs for everything in Python

#65
post #63
post #52

Earlier quoted context omitted.

Is this safe in all cases? What about complex types? Specifically if you assign a variable to an element in the array, and then replace the element in the array? You'd have to take care not to update the value of the variable.

Assigning a variable to a destination declared to be an incompatible type should produce an error at compile time if possible, and at at run time otherwise. That's what type declarations are all about.

I think you misunderstand. Here's an example:

``` foos = [Foo(a=0), Foo(a=1)] f0 = foos[0] foos[0] = Foo(a=2)

print(f0.a) # 0 print(foos[0].a) # 2 ```

`foos` is a list of type `Foo`, but it still can't be safely made into a dense list (at least not naively).

Re: Using attrs for everything in Python

#66
post #31

It feels a bit hampered by "bad" design decisions to me I think its safe to say that the current view of what decorators do is, a) filter things going to functions (so they error, or hit a cache), or b) register a function with another library (e.g. flask path decorator) This library does a lot more than that, so it seems that maybe a metaclass (which exists to mutate the class's creation) would be more appropriate?…

Agreed. From the post, it seems to me like another (IMO better) alternative to this awkward attr-specific convention and syntax etc would be to create a factory function for dynamic class definition, in a similar vein to namedtuples. This is functionally similar to the metaclass route, and to be honest I'm not sure what the tradeoffs would be. Either way, I think metaprogramming is a much better approach than attrs i…

There is one:

>>> C2 = attr.make_class("C2", ["a", "b"])

>>> C2("foo", "bar")

C2(a='foo', b='bar')

Re: Using attrs for everything in Python

#67
post #30

"Another place you probably should be defining an object is when you have a bag of related data that needs its relationships, invariants, and behavior explained. Python makes it soooo easy to just define a tuple or a list." Yes, and defining a tuple or a list is often better than a small object because of Python's problems with serializing (pickling) objects. If you're doing anything with data, anything functional, a…

None of this is a problem with attrs. Serialize however you like.

    >>> import attr
    >>> 
    >>> @attr.s
    ... class Thing(object):
    ...     a = attr.ib()
    ...     b = attr.ib()
    ...     
    ... 
    >>> @attr.s
    ... class Many(object):
    ...     things = attr.ib()
    ...     
    ... 
    >>> many = Many([Thing(1, 2), Thing(3, 4)])
    >>> many
    Many(things=[Thing(a=1, b=2), Thing(a=3, b=4)])
    >>> attr.asdict(many)
    {'things': [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}]}
    >>> import pickle
    >>> pickle.dumps(many)
    "ccopy_reg\n_reconstructor\np0\n(c__main__\nMany\np1\nc__builtin__\nobject\np2\n
    Ntp3\nRp4\n(dp5\nS'things'\np6\n(lp7\ng0\n(c__main__\nThing\np8\ng2\nNtp9\nRp10\
    n(dp11\nS'a'\np12\nI1\nsS'b'\np13\nI2\nsbag0\n(g8\ng2\nNtp14\nRp15\n(dp16\ng12\n
    I3\nsg13\nI4\nsbasb."
    >>> import json
    >>> json.dumps(attr.asdict(many))
    '{"things": [{"a": 1, "b": 2}, {"a": 3, "b": 4}]}'
    >>>

Re: Using attrs for everything in Python

#68
post #59

Hmm, IDK. Stuff like @attr.ib is kind of cute looking. (This not being a good thing). Though in reality, I'd probably want more explicit methods. If you are using something like Django REST framework, you can validate with the serializer. And sometimes you want to validate (often) the combination of variables and how they interact. Kind of feels a little non-pythonic to me. Clever, but the ways it is changing things…

From the docs: (If you don’t like the playful attr.s and attr.ib, you can also use their no-nonsense aliases attr.attributes and attr.attr).

I would consider that a negative.

> There should be one-- and preferably only one --obvious way to do it.

Whats going to happen when all professional code is using `attr.attributes` but all the documentation uses `attr.s`?

Anyway its a minor point. I personally think it is a poor decision when a programmer decides to be cute than clear.

Re: Using attrs for everything in Python

#70
post #2

This seems nice, but other than easy destructuring of functions that return long tuples (which really should return dicts), I cannot figure out a good use case for it over using a dictionary. I am keen to hear others' opinions.

Dictionaries are not for fixed fields.

if you have a dict, it maps something to something else. You should be able to add and remove values.

Objects, on the other hand, are supposed to have specific fields of specific types, because their methods have strong expectations of what those fields and types are.

attrs lets you be specific about those expectations; a dictionary does not. It gives you a named entity (the class) in your code, which lets you explain in other places whether you take a parameter of that class or return a value of that class.

Post reply on HN