Simplifying anonymous inner classes?

T

Tim Chase

I've got code similar to the following

class Action:
def __init__(self, ...): pass
def __call__(self, ...): pass
def get_help(self, ...): pass

class Backend:
class _Load(Action):
def __init__(self, ...): pass # override1
def __call__(self, ...): pass # override1
def get_help(self, ...): pass # override1
load = _Load(...)
class _Run(Action):
def __call__(self, ...): pass # override2
def get_help(self, ...): pass # override2
run = _Run(...)

class DatabaseBackend(Backend):
class _Frob(Action):
def __init__(self, ...): pass # override3
def __call__(self, ...): pass # override3
def get_help(self, ...): pass # override3
frob = _Frob(...)

In certain other languages, I might reach for an anonymous inner
class -- however, I don't see any way to do something like

class Backend:
load = (class Action:
def __init__(self, ...): pass # override1
def __call__(self, ...): pass # override1
def get_help(self, ...): pass # override1
)(...args to __init__...)
run = ...

It seems silly to define the inner classes _Load and _Run just to
create a single instance of them (and for all it matters the
_Load and _Run could be promptly deleted from the containing
namespace immediately after instantiation). Method
implementations are sufficiently complex that a lambda won't
suffice (or if they would, they're beyond my know-how).

Is there a more Pythonic way to instantiate sub-classes and
provide instance-specific implementations without the overhead of
an unused "anonymous" class cluttering my code/namespace?

Thanks,

-tkc


PS: part of the aim is to have properties that can be discovered
through introspection, know how to provide help on themselves,
and have a protocol for parameter-discovery for the __call__ method.
 
P

Peter Otten

Tim said:
I've got code similar to the following

class Action:
def __init__(self, ...): pass
def __call__(self, ...): pass
def get_help(self, ...): pass

class Backend:
class _Load(Action):
def __init__(self, ...): pass # override1
def __call__(self, ...): pass # override1
def get_help(self, ...): pass # override1
load = _Load(...)
class _Run(Action):
def __call__(self, ...): pass # override2
def get_help(self, ...): pass # override2
run = _Run(...)

class DatabaseBackend(Backend):
class _Frob(Action):
def __init__(self, ...): pass # override3
def __call__(self, ...): pass # override3
def get_help(self, ...): pass # override3
frob = _Frob(...)

In certain other languages, I might reach for an anonymous inner
class -- however, I don't see any way to do something like

class Backend:
load = (class Action:
def __init__(self, ...): pass # override1
def __call__(self, ...): pass # override1
def get_help(self, ...): pass # override1
)(...args to __init__...)
run = ...

It seems silly to define the inner classes _Load and _Run just to
create a single instance of them (and for all it matters the
_Load and _Run could be promptly deleted from the containing
namespace immediately after instantiation). Method
implementations are sufficiently complex that a lambda won't
suffice (or if they would, they're beyond my know-how).

Is there a more Pythonic way to instantiate sub-classes and
provide instance-specific implementations without the overhead of
an unused "anonymous" class cluttering my code/namespace?

Python 2.6 has class decorators:
.... def __init__(self, *args):
.... self.args = args
.... def __call__(self, class_):
.... return class_(*self.args)
........ @instantiate(1,2)
.... class load:
.... def __init__(self, x, y):
.... self.x = x
.... self.y = y
.... def __str__(self):
.... return "load(%s, %s)" % (self.x, self.y)
....load(1, 2)

For older Pythons you can put the class into a function:
.... def __init__(self, *args):
.... self.args = args
.... def __call__(self, make_class):
.... return make_class()(*self.args)
........ @instantiate(1,2)
.... def load():
.... class Load:
.... def __init__(self, x, y):
.... self.x = x
.... self.y = y
.... def __str__(self):
.... return "load(%s, %s)" % (self.x, self.y)
.... return Load
....load(1, 2)

While the class namespace isn't "cluttered" it's all a bit too complex to be
truly pythonic.

Peter
 
T

Tim Chase

PS: part of the aim is to have properties that can be discovered
Without a more concrete example it is hard to tell what you are trying to
achieve. Python already allows you to discover methods and properties
through instrospection, a standard method for them to provide help on
themselves and standard ways to inspect parameters. Are you adding some
value or just inventing a wheel with more sides?

It's an application with multiple back-ends (web, DB, textfile)
and multiple front-end UIs (command-line, web, IM). Yes,
Python's introspection could determine the parameters to a
function, but providing help on them is a bit unwieldy (and
processing the motley assortment of parameters from a list of
args becomes more complex). Each Action contains an optparse
parser that knows how to deal with that particular action's list
of parameters, as well as provide documentation on that
parameter, allow for defaults, parse more complex action
syntaxes, etc. All front-end requests are transformed into this
syntax as an array of arguments to be passed to the Action.

As a common ground with which you're hopefully familiar, consider
the interface to your typical VCS such as cvs/svn/hg/bzr/git:

vcs [global options] <command> [command options] [args]

Each of those <commmand>s maps to an Action where the [command
options] can be discovered based on the implementation of
<command>, the help for that command can be readily generated,
and all the other power of optparse (defaults values, custom
parsing, option grouping, parameter synonyms, etc) are available.
The IM interface takes <command> onward accepted as messages,
and the CGI web interface takes GET/POST requests and translates
them into the corresponding command/options/args. Thus, the
actual call signatures are more accurrately

def __init__(self, ...):
self.parser = optparse.OptionParser(...)
def __call__(self, argv): # argv is a list like sys.argv
options, args = self.parser.parse_args(argv)
# do something with options/args

So that background provided, the original question was more about
how to create anonymous sub-classes with overridden methods so my
Backend objects' code & namespaces weren't littered with objects
that were only defined to be instantiated once in exactly the
location they were defined.

-tim
 
C

Carl Banks

I've got code similar to the following

  class Action:
    def __init__(self, ...):  pass
    def __call__(self, ...):  pass
    def get_help(self, ...):  pass

  class Backend:
    class _Load(Action):
      def __init__(self, ...): pass # override1
      def __call__(self, ...): pass # override1
      def get_help(self, ...): pass # override1
    load = _Load(...)
    class _Run(Action):
      def __call__(self, ...): pass # override2
      def get_help(self, ...): pass # override2
    run = _Run(...)
[snip]

Is there a more Pythonic way to instantiate sub-classes and
provide instance-specific implementations without the overhead of
an unused "anonymous" class cluttering my code/namespace?

Just delete the names after instantiating the class:

del _Load
del _Run

I'm not trying to be snarky, sometimes the straightforward way is the
best.

I like Peter Otten's class decorator solution to this also, and
disagree that such complexity is necessarily unPythonic. If you do it
a lot the complexity could result in an overall simplification. It's
not something you want to casually throw at users, though.

A way to do this in 2.5 and below is to use a class hook (using
__metaclass__ attribute):

def self_instantiate(name,bases,clsdict):
cls = type.__new__(type,name+"_type",
bases,clsdict)
obj = cls()
return obj

class load(Action):
__metaclass__ = self_instantiate
....



Carl Banks
 
A

Arnaud Delobelle

Tim Chase said:
I've got code similar to the following

class Action:
def __init__(self, ...): pass
def __call__(self, ...): pass
def get_help(self, ...): pass

class Backend:
class _Load(Action):
def __init__(self, ...): pass # override1
def __call__(self, ...): pass # override1
def get_help(self, ...): pass # override1
load = _Load(...)
class _Run(Action):
def __call__(self, ...): pass # override2
def get_help(self, ...): pass # override2
run = _Run(...)

class DatabaseBackend(Backend):
class _Frob(Action):
def __init__(self, ...): pass # override3
def __call__(self, ...): pass # override3
def get_help(self, ...): pass # override3
frob = _Frob(...)

In certain other languages, I might reach for an anonymous inner class
-- however, I don't see any way to do something like

class Backend:
load = (class Action:
def __init__(self, ...): pass # override1
def __call__(self, ...): pass # override1
def get_help(self, ...): pass # override1
)(...args to __init__...)
run = ...

It seems silly to define the inner classes _Load and _Run just to
create a single instance of them (and for all it matters the _Load and
_Run could be promptly deleted from the containing namespace
immediately after instantiation). Method implementations are
sufficiently complex that a lambda won't suffice (or if they would,
they're beyond my know-how).

Is there a more Pythonic way to instantiate sub-classes and provide
instance-specific implementations without the overhead of an unused
"anonymous" class cluttering my code/namespace?

Thanks,

-tkc


PS: part of the aim is to have properties that can be discovered
through introspection, know how to provide help on themselves, and
have a protocol for parameter-discovery for the __call__ method.

Here's a way to do it in python 2.2+:

def instance(*args, **kwargs):
class MetaInstance(type):
pass

class Instance(object):
__metaclass__ = MetaInstance

@staticmethod
def MetaInstance__new__(meta, name, bases, attrs):
bases = list(bases)
bases.remove(Instance)
cls = type(name.capitalize(), tuple(bases), attrs)
return cls(*args, **kwargs)

MetaInstance.__new__ = MetaInstance__new__

return Instance

How to use it:
.... def foo(self): return 'A.foo'
.... .... def __init__(self, x): print 'This B is given ', x
.... def bar(self): return 'B.bar'
....
This B is given 42
(There may be a simpler way to do it, I've just adapted something else
to what you require)
 
M

Martin v. Löwis

Is there a more Pythonic way to instantiate sub-classes and provide
instance-specific implementations without the overhead of an unused
"anonymous" class cluttering my code/namespace?

I agree with Carl Banks that what you do is already fairly Pythonic:
explicit is better than implicit, and simple is better than complex.
What you do *is* simple, and easy to read - no magic involved.
You wish it to be more concise - but I think that would make *less*
pythonic, not more.
PS: part of the aim is to have properties that can be discovered through
introspection, know how to provide help on themselves, and have a
protocol for parameter-discovery for the __call__ method.

I agree with Duncan Booth that what you want to implement through
objects is perhaps already available in methods. For example,
you might use function decorators to create the option definitions.

So you could write

class DatabaseBackend:
@Action("load a thang into memory").
add_option("-f", "--file", help="load from file").
add_option(...)
def load(self, args):
...

Notice that the name of the command can be reflected from the
method's __name__, so I don't need to pass it into the Action
constructor. To implement the decorator, I suggest to just set
a function attribute, and return the original function.

HTH,
Martin
 
T

Tim Chase

Is there a more Pythonic way to instantiate sub-classes and
I agree with Carl Banks that what you do is already fairly
Pythonic: explicit is better than implicit, and simple is
better than complex. What you do *is* simple, and easy to read
- no magic involved. You wish it to be more concise - but I
think that would make *less* pythonic, not more.

After playing with the various solutions (hurray for
version-control), I find myself back where I started, agreeing
with Carl & Martin for the most part. Everything else ended up
looking so baroque that it made matters worse. Even the extra
"del" statements for cleaning up the namespace were extra clutter
in the code, so I didn't bother tidying the namespace. I did
switch from

do_foo = _Foo(args)
do_bar = _Bar(args)

to having each backend contain a list of available actions, so I
simply maintain

self.actions = set([
_Foo(args),
_Bar(args),
_Baz(args),
])

(each Action knows how to hash itself for entry in a set) and
then descendants of Backend (such as DBBackend) simply add to
this set of actions in their own __init__ call.

The final product is what I'd call a "most understandable/least
convoluted" solution which, in the big picture, seems to be a
good part of "pythonicity". Until such time as Python offers
anonymous classes natively :)

Thanks to all who offered suggestions.

-tkc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top