Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Are ABCs an anti-pattern?

87 views
Skip to first unread message

Demian Brecht

unread,
Oct 2, 2012, 10:23:05 AM10/2/12
to Python
I don't use them anymore, but I'm curious about others opinions on this
list...

The more time I spend in Python, discovering what "Pythonic" code is and
such, it seems that I throw away much in terms of academic learnings as
far as "OOP correctness" goes. In doing so, I find that, in general,
overall LOC (yes, I'm aware that this is a poor metric to judge anything
on), readability and overall quality of code seems to go up. Yes, you
give the user much more rope to hang themselves with making the general
assumption that the user knows what they're doing, but we're all
consenting adults here after all, right? ;)

As an example, I initially had an OAuth 2.0 client library that was
roughly 450 LOC (using ABCs, adapter patterns for the various flows,
etc). Dropping this for a more "Pythonic" (at least, what my
interpretation of Pythonic code is) brought the entire library down to
55 LOC. Having said that, the decline in LOC and overall grok-ability
wasn't entirely due to moving away from ABCs and dropping the use of
adapters, but it did have quite a bit to do with it).

As such, I see ABCs as somewhat of an anti-pattern in the Python world.
The concept is obviously essential in non-duck-typed language using
strict OOP, but does it *really* belong in Python?

--
Demian Brecht
@demianbrecht
http://demianbrecht.github.com

Terry Reedy

unread,
Oct 2, 2012, 2:55:54 PM10/2/12
to pytho...@python.org
ABCs were added (fairly recently) in 3.0 for the reasons given in
http://python.org/dev/peps/pep-3119/
It was expected that it would take awhile for them to see good, pythonic
uses. We obviously did okay without them up to 2.7.

They are partly informational, partly meant to help duck typing. I don't
think they are used much in the stdlib (except to register classes) and
I have not used them myself.

--
Terry Jan Reedy

Trent Nelson

unread,
Oct 5, 2012, 3:58:37 PM10/5/12
to Demian Brecht, Python
On Tue, Oct 02, 2012 at 07:23:05AM -0700, Demian Brecht wrote:
> I don't use them anymore, but I'm curious about others opinions on this
> list...

I like them. In particular, I like that I can enumerate all the
subclasses that happen to implement the ABC via the metaclass's
__subclasses__() method. I also like that I can trust Python
not to instantiate a subclass of an ABC unless it meets all the
interface criteria I've stipulated.

Both of these aspects make ABCs a great fit when your base classes
will be subclassed by other users/libraries (i.e. that you have no
control over).

For example, I use them in a project of mine called Enversion in
order to automatically generate command-line scaffolding with as
little effort (programming/typing-wise as possible). The ABC
stuff lives in 'evn.cli' and provides a set of generic classes
for command-line tools.

One of the command line tools that ships with Enversion is the
'evnadmin' command. Thanks to all the ABC scaffolding in the
'evn.cli/command' module, all I need to write is the following
to get an 'evnadmin' command-line interface:

from evn.cli import (
CLI,
CommandLine,
)

class AdminCommandLine(CommandLine):
@property
def commands_module(self):
return evn.admin.commands

class AdminCLI(CLI):

@property
def program_name(self):
return 'evnadmin'

@property
def commandline_subclasses(self):
return AdminCommandLine.__subclasses__()

class DoctestCommandLine(AdminCommandLine):
_quiet_ = True

class DumpDefaultConfigCommandLine(AdminCommandLine):
pass

class DumpConfigCommandLine(AdminCommandLine):
_conf_ = True

class ShowConfigFileLoadOrderCommandLine(AdminCommandLine):
_conf_ = True

class DumpHookCodeCommandLine(AdminCommandLine):
_conf_ = True
_repo_ = True

[snip]

Running 'evnadmin' with no arguments yields this:

% evnadmin
Type 'evnadmin <subcommand> help' for help on a specific subcommand.

Available subcommands:
analyze
create
disable-remote-debug (drd)
doctest
dump-config (dc)
dump-default-config (ddc)
dump-hook-code (dhc)
enable
enable-remote-debug (erd)
find-merges (fm)
fix-hooks (fh)
root-info (ri)
run-hook (rh)
show-config-file-load-order (scflo)
show-repo-hook-status (srhs)
show-repo-remote-debug-sessions (srrds)
show-roots (sr)
toggle-remote-debug (trd)
version

The scaffolding can generate all of that automatically thanks to the
ability to enumerate __subclasses__() of a metaclass. The fact that
Python will bomb out if a derived class doesn't implement all the
required methods/properties is icing on the cake. When you are
expecting other developers to leverage your ABCs, getting instant
feedback when you forget to implement a required method/property
is incredibly useful. It's definitely not a case of battling the
design decisions made by the ABC author...

Relevant Python files:
https://github.com/tpn/enversion/blob/master/evn/cli.py
https://github.com/tpn/enversion/blob/master/evn/admin/cli.py

Regards,

Trent.

> Demian Brecht
> @demianbrecht
> http://demianbrecht.github.com
> --
> http://mail.python.org/mailman/listinfo/python-list

Demian Brecht

unread,
Oct 6, 2012, 6:45:23 PM10/6/12
to Trent Nelson, Python
On 12-10-05 12:58 PM, Trent Nelson wrote:
> I like them. In particular, I like that I can enumerate all the
> subclasses that happen to implement the ABC via the metaclass's
> __subclasses__() method.
As long as you have a common base class (which in your case is a
requirement), then __subclasses__ works for introspecting child classes.
It doesn't *really* have anything to do with abcs.

> I also like that I can trust Python
> not to instantiate a subclass of an ABC unless it meets all the
> interface criteria I've stipulated.
Another way to read this is that you don't trust those using your code
to be bright enough to understand what your code is doing and what it
requires. In my mind, this seems to somewhat contradict the philosophy
of "we're all consenting adults here". Whether you utilize interfaces or
not, code should be documented. Your documentation would be responsible
for laying out the expected interface (again, whether you're using the
interfaces or not). Code would fail at some point if a requirement on an
interface hasn't been filled. The *one* nice thing is that it'll error
on import rather than execution time, but to me, if your code is unit
tested, then all these things should be caught almost immediately anyway.

From my experience (again, *only* talking about Python here), it seem
to me that less is generally more. Less code means less things to read
and tie together, making it easier to grok overall (not to mention less
overhead for the interpreter, but that's virtually moot due to the
*very* little overhead in 99% of cases of uses features such as abcs).
Using abcs not only lends itself to code bloat, but it also leads to
over-engineering as once you fall into old OOP habits, you start getting
back to un-Pythonic code (pretty subjective statement, I know :)).


Again, please don't misunderstand my intentions here. I'm not arguing
the need for abstract base classes in a strict OOP world. I'm arguing
them as not genuinely being Pythonic.


Thanks for your the feedback so far.

--
0 new messages