[Python-Dev] Confirming status of new modules in 3.4 (original) (raw)
Nick Coghlan ncoghlan at gmail.com
Sun Mar 16 03:45:52 CET 2014
- Previous message: [Python-Dev] Confirming status of new modules in 3.4
- Next message: [Python-Dev] Confirming status of new modules in 3.4
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 16 March 2014 09:00, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
Nick Coghlan wrote:
On 16 March 2014 01:40, Guido van Rossum <guido at python.org> wrote:
This downside of using subclassing as an API should be well known by now and widely warned against.
I've actually pondered the idea of suggesting we explicitly recommend the "procedural facade around an object oriented implementation" API design model in PEP 8, I don't think I would call this a "procedural" API. To my mind, any API that exposes objects with methods is an object-oriented API, whether it encourages subclassing those objects or not.
There are actually two variants of the approach. One is obviously procedural: you put basic data types (strings, numbers, containers, etc) in, you get basic data types out, and the fact an object managed the calculation in the middle is completely opaque to you as a user of the API. (from the outside, it still looks like a pure function, even though the internal calculation may have been highly stateful)
The second variant is better exemplified by an API like contextlib.contextmanager(). That decorator returns a custom object type (now called contextlib._GeneratorContextManager). That type was originally undocumented with the name contextlib.GeneratorContextManager, and when the discrepancy was pointed out, I resolved it by adding the missing underscore (in 3.3 IIRC, could have been 3.2), rather than by documenting something I considered to be an implementation detail.
The key problem this addresses is that telling people "this is a class" often overspecifies your API, because classes have a very broad interface. They support inheritance, typechecks, etc, etc. It's a really big commitment to your API users, and not one you should make lightly. Subclassing an object is also an extremely high coupling technique - it's genuinely difficult to refactor classes in any meaningful way with risking breakage of subclasses.
As an example of unanticipated coupling issues that inhibit refactoring, consider a class where "method B" is originally written to call "method A". You later notice that this would be better structured by having both methods A and B call a new helper method C, rather than having B call A. If "method A" was a public API you now have a problem, since after the change, a subclass that previously only overrode A will now see different behaviour in method B (because that is now bypassing the override in the subclass). It can all get very, very messy, so experience has taught me that making your classes part of your public API before you're 100% certain you're happy with not only the public methods, but also the relationships between them, is a fine recipe for locking in bad design decisions in a hard to fix way. Sometimes the trade-off is worth it due to the power and flexibility that API users gain, but it needs to be recognised as the very high coupling technique that it is.
By contrast, a callable API like contextlib.contextmanager just says "given a certain set of inputs, you will get some kind of object back with these characteristics, no more, no less". It is, in essence, ducktyping as applied to return types :)
Cheers, Nick.
-- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
- Previous message: [Python-Dev] Confirming status of new modules in 3.4
- Next message: [Python-Dev] Confirming status of new modules in 3.4
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]