8 ms·
This sounds fun if you have 10x programmers or at least IQ > 140 programmers in charge. Last place I worked, I was told never use "smart" tricks if you can do t
by red_admiral 2y ago
This sounds fun if you have 10x programmers or at least IQ > 140 programmers in charge. Last place I worked, I was told never use "smart" tricks if you can do the same thing in a simpler way. For-else and f-strings and := sound like harmless enough (though the last one is controversial); "with" is useful for resources that need to be deallocated but "yield"? Really? "more readable" when you slap a decorator on the thing? Why are we packing the enter and exit operations into a single function?
Playing with the typesystem and generics like this makes me worry I'm about to have a panic attack.
Give me code that I can understand and debug easily, even when I didn't write it; don't do implicit magical control flow changes unless you have a very good excuse, and then document both the how and the why - and you'll get a product that launches earlier and has fewer bugs.
Sometimes, a few more if statements here and there make code that is easier to understand, even if there's a clever hack that could cut a line or two here and there.
- hk__2 2y agoI don’t really see "smart tricks" here, just features of the language that you may not be aware of. I use most of them in my daily work without thinking about it: `@overload` and other typing features are useful to document the code, prevent mistakes, and help IDEs generate more helpful suggestions; keyword-only arguments force users to pass options as keywords, so you avoid calls like `foo(x, z, z, true, true, false, true)` and ensure the code is more explicit; for-else can sometimes clarify some complicated code; the walrus operator, short-circuiting with `or`, and chaining operators are just normal Python.
- mpeg 2y agooverload is very useful, but I find some people mistakenly think it actually modifies the runtime function signature to do multiple dispatch, so I do try to avoid it in favour of simpler functions whenever possible too many overloads can be a code smell IMHO, it's ok when you are implementing a very common pattern and want proper types (decorators come to mind, so that both @decorator and @decorator() work, where the decorator might also have optional args) but I think in cases like the example in the article it should almost always be two separate functions
- at_a_remove 2y agoI strongly agree. The walrus operator ... argh. When I code, I try to make everything I write not clever. I am not saving a byte here and there because I am not typing in a program from a magazine in the 1980s (I was there, I am not going back). No code golf. I did my time on the Timex-Sinclair with its miserable two kilobytes of memory and reserved keywords as special-function strokes at a character each. Each line should do one thing, in general, and it ought to be obvious. Cleverness is held in reserve for when it is truly needed, namely data structures and algorithms. One of my accomplishments which seems to have mattered only to me is when my apartment-finding/renting system, written entirely in Perl, was transferred into the hands of students, new programming students. Perl is famously "write-once, read-never" and seems to have a culture favoring code golf and executable line noise. Still, the students got back to me and told me how easily-ported everything was, because I had done just one thing per line, avoided $_ and other such shortcuts, and other practices. They were very happy to take it over because I had avoided being cryptic and terse.
- mpeg 2y agoI don't fully disagree, but the yield context manager approach is very common when writing test fixtures, you do: # setup yield resource. # teardown Not that it makes it any less magical, but at least it's a consistent python pattern
- red_admiral 2y agoTest fixtures as opposed to production code forgive a multitude of sins. Sometimes you have to mock up an object that could never exist in the real world, to assert that the main code doesn't just accept it and move on. Sometimes you poke at individual variables in an object that in the real world should only be accessed via the methods in its API. All in a day's work if you know what you're doing and never try that in the real code.
- tomn 2y agoThe simple contextlib.contextmanager example doesn't really sell the benefits. The main one is that it makes error handling and clean-up simpler, because you can just wrap the yield with a normal try/catch/finally, whereas to do this with __enter__ and __exit__ you have to work out what to do with the exception information in __exit__, which is easy to get wrong: https://docs.python.org/3/reference/datamodel.html#object.__exit__ https://docs.python.org/3/reference/datamodel.html#object.__... Suppressing or passing the exception is also mysterious, whereas with contextlib you just raise it as normal. Another is that it makes managing state more obvious. If data is passed into the context manager, and needs to be saved between __enter__ and __exit__, that ends up in instance variables, whereas with contextlib you just use function parameters and local variables. Finally, it makes it much easier to use other context managers, which also makes it look more like normal code. Here's a more real-world-like example in both styles: https://gist.github.com/tomjnixon/e84c9254ab6d00542a22b7d79945ef2b https://gist.github.com/tomjnixon/e84c9254ab6d00542a22b7d799... I think the first is much more obvious. You can describe it in english as "open a file, then try to write a header, run the code inside the with statement, write a footer, and if anything fails truncate the file and pass the exception to the caller". This maps exactly to the lines in the contextlib version, whereas this logic is all spread out in the other one. It's also more correct, as the file will be closed if any operation on it fails -- you'd need to add two more try/catch/finally blocks to the second example to make it as good.