7 ms·
If you're interested in Python anti-patterns instead, we wrote an open-source book on them a while ago: https://docs.quantifiedcode.com/python-anti-patterns/ ht
by ThePhysicist 5y ago
If you're interested in Python anti-patterns instead, we wrote an open-source book on them a while ago: https://docs.quantifiedcode.com/python-anti-patterns/ https://docs.quantifiedcode.com/python-anti-patterns/
Hasn't received any updates in the last years but it still holds up quite well, disregarding the Python 2 specific anti-patterns of course which become less and less relevant, as well as the Django-specific ones, which probably are hopelessly outdated.
- IshKebab 5y agoNot a bad list. Feels like most of them should just be linter rules. I also found a few them don't really apply if you're using static types (which you really really really should), e.g. * Returning more than one variable type from function call: That's fine; the type checker will make sure you don't make a mistake. * Asking for permission instead of forgiveness: Makes sense for the example given (`unlink`) but it is better to e.g. check types explicitly with `isinstance()` than to catch `TypeError`.
- ThePhysicist 5y agoYes absolutely, that book was written before type annotations made it into Python though.
- refactor_master 5y agoAsking for permission instead of forgiveness can easily become an anti-pattern in itself, because it allows lazy code that turns `if known type has expected property` into `try prodding this Any object, and catch where it blows up later`
- xvedejas 5y agoThis seems to be missing my biggest gripe: adding new attributes to classes outside of `__init__()` or `__slots__`. Sadly I have to deal with code that does this with some frequency. Sometimes the attribute is added and accessed outside of instance methods entirely, ad-hoc by some caller. The result is total spaghetti. It becomes impossible to really know what the "interface" of the class is when you have to consider this, plus multiple inheritance, plus metaclasses, and then on top of that someone decided to hijack `__getattr__`. If I have to comb through the entire codebase to understand one class, that's a huge antipattern. To avoid this, a lot of the new Python code I write is full of dataclasses. I do feel like I'm leaving a little bit of power on the table, but at least I can understand the code at a glance.
- hermitdev 5y ago> This seems to be missing my biggest gripe: adding new attributes to classes outside of `__init__()` or `__slots__`. You don't strictly need to use dataclasses to accomplish this. Yes, you get stronger guarantees with dataclasses (such as runtime checks, and these come with a runtime cost), but you can declare your members the same and use a properly configured linter that will tell you if you're assigning members from places you shouldn't. Personally, I tend use dataclasses more for plain old data types. As soon as one starts needing/wanting to control __init__, I find the utility of dataclasses drops precipitously. But, I do still annotate my (public) members with proper types, trying to avoid `Any` as much as possible.
- BerislavLopac 5y agoOn a quick scan over the ToC, one important anti-pattern seems to be missing - automated code generation.
- srvmshr 5y agoHonest question: I hear these terms used quite a bit. What qualifies as patterns/anti-patterns? (From my naive understanding, patterns are some language features which should be used over conventionally accepted ways. Please correct if wrong)
- lmm 5y agoPatterns are not really language features so much as the lack of them - they're "standardised" ways of solving a problem that the language doesn't have a feature for, so that at least everyone is writing the same thing and a reader might be able to understand the code at a glance. Anti-patterns are pretty much the same thing, just where there is some problem with the common solution that everyone is using - perhaps there actually is a language feature that addresses this use case after all, for example.
- srvmshr 5y agoSo if I write a recursive function to calculate factorial of a number (or some permutation calculator), will that be considered a pattern? Because Python3 wouldn't have the factorial built-in. Thank you for the explanation above.
- lmm 5y agoOnce isn't a pattern, factorial isn't normally seen as a language feature. Implementing recursion via the Y combinator is a pattern (for languages that don't have built-in recursion) because you do it again and again for many different functions.
- bb88 5y ago__init__.py shouldn't contain any "business logic" other than exposing symbols.
- zbentley 5y agoValidation?
- bb88 5y agoUnit tests. You only need to validate things once typically. Why force the user to run validation code over and over on a code base unlikely to change?
- zbentley 5y agoOh, fair enough. I had misread the GP comment as being about __init__ (constructor methods) rather than __init__.py, package re-export. I'd make a small and mostly pedantic exception to "nothing but re-exports in __init__.py" for cases where you have a module with data (non-Python) files adjacent to the code, but which doesn't need more than one Python file to define its module logic. No point to have a tiny __init__.py that re-exports from an adjacent somemodule.py in that case. But generally yes, you're right.