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 see if it's that much of a boost.
> For those who can’t swallow that API at all, attrs comes with serious business aliases: attr.attrs and attr.attrib.
I'm definitely in the can't swallow camp. There's no precedent for using attribute namespaces to name things with half the name on one side and half the name on the other side, so who the hell does this project think it is to start doing it? :) Seriously though I'm pretty sure I hate it.
And I'm having trouble liking the "proper" names. So we use a class decorator "@attrs" to declare "this class is going to use class attributes to declare available instance attributes slots, a bit like django or schematics fields". Maybe it would have been better to call it "@attrs.model" since it is essentially a model definition in the terminology of other data modeling projects?
from attr import (
s as AttributedModel,
ib as attribute,
)
@AttributedModel
class Bar(object):
x = attribute()
y = attribute()
0: https://gist.github.com/gknoy/6e884fce3edda08a1566823fec37ba...attr.ib = "attirb" = alternate spelling of "attr"
It's too cute by half.
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).
Aside from that, this is not a fair comparison because attr names can, and mostly should be, longer, and there can be more of them, e.g.:
class SomeClass(object):
def __init__(self, myattr1, some_val, a_bool,
my_other_attr):
self.myattr1 = myattr1
self.some_val = some_val
self.a_bool = a_bool
self.my_other_attr = my_other_attr
And of course they'll need to go into __str__ method as well."Explicit is better than implicit"
Compare:
with open("file.txt") as somefile:
for line in somefile:
print line
To the more explicit and clear: somefile = open("file.txt")
line = somefile.readline()
while line:
print line
line = somefile.readline()
somefile.close()
But I'm still using some magic, I should be more explicit: def explicit_readline(fd):
buff = []
char = fd.read(1)
while char != "\n" and char != "":
buff.append(char)
return "".join(buff)
somefile = open("file.txt", "rb") # just to be sure now
line = explicit_readline(somefile)
while line != "": # to be more explicit, of course
print line
line = explicit_readline(somefile)
somefile.close()
And we could go on like this to replace open with the os module file-descriptor functions, and print with sys.stdout/stderr (because more explicit, right?). But even without getting there, it should be obvious that:* The "explicit" verison no longer behaves as the original one, because, for example, explicit_readline only handles well the NIX newline character. If I want to provide the same functionality as file.readline() I should add a lot more code.
I've reinvented the wheel for no good reason, and readability has suffered. It may also leave a lingering question in the mind of a read "why did he do that? is there some edge case that wasn't well documented anywhere and he bumped into?".
* I've seen more contrived code do a version of this "more explicit" programming style, to the point of having statements like:
def f1(number):
number = int(number)
return number & 0xff00 # or plug the number parameter in an equation, etc
* ... (not a verbatim example, but along those lines). And that code is redundant and it will fail anyway if another thing other than an int/long/float is passed. It would be certainly saner to have an assert, or simply specify in the docs that said function expects a number (which is implied in the args too).My point was the "Explicit is better than implicit" means "be clear of your intent". And if I see someone using the attr module (which comes with the standard library), and I'm not familiar with it, I'll read into it. And for it's use case, I think it's clear enough in what it does, and how it should be used.
...wait wat? It's in the Standard Library? No, I just checked and it's not. Too bad, if it was "blessed" by inclusion in the library I would totally withdraw my objection on that grounds.
You had me going for a second there. ;-)
You make my point for me though when you say that you'd have to read up on it when you first encountered it. That's exactly my point:
The trade off is between one application of attr to the code base to save N time/effort for the current developer one time, versus every bit of lost time/effort of future devs taken to understand the attr package.
It's cute, but it's an in-joke. Don't put in-jokes in code you want other people to use, otherwise they have to "get the joke" before they can work with it. That's what I'm on about.
On my Linux machine (Python 2.7.6) I can't import it without a previous install from pip install (that's reasonable).
Can't track down much about why this happens because googling "python attr" brings results about hasattr, getattr, etc, but few about the attr module.
- "def" instead of "define"
- "cls" instead of "Class"
- "sys" instead of "system"
- "os" instead of "operating_system_facilities"
- "ntpath" instead of "windows_path_names"
- "abc" instead of "abstract_base_classes"
Python aggressively abbreviates almost everything in common use. If it were in the stdlib, perhaps it would be the built-in names "attrs" and "attrib" rather than having dots in them, but the names would indubitably still be very short.
With just runs the enter and exit method of a context manager. Nothing magical about it.
>My point was the "Explicit is better than implicit" means "be clear of your intent". And if I see someone using the attr module (which comes with the standard library), and I'm not familiar with it, I'll read into it.
You don't have to read into 'with' to make an intelligent guess at what the code does. It's meaningful even if you've never heard of context managers.
Unlike this.
I've been using Python for a while, but it's not my main development language. I mainly use it for scripting experiments, processing data and generating graphs. I generally avoid defining classes as much as possible, and use namedtuple whenever appropriate.
This:
...is much easier to read than this: Readability is what I love about Python. I don't think the conciseness of attrs is worth the loss in readability.