By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,583 Members | 1,770 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,583 IT Pros & Developers. It's quick & easy.

Simplifying anonymous inner classes?

P: n/a
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.


Nov 1 '08 #1
Share this Question
Share on Google+
8 Replies


P: n/a
Tim Chase <py*********@tim.thechases.comwrote:
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.
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?
Nov 1 '08 #2

P: n/a
Tim Chase wrote:
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:
>>class instantiate(object):
.... def __init__(self, *args):
.... self.args = args
.... def __call__(self, class_):
.... return class_(*self.args)
....
>>class Backend:
.... @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)
....
>>print Backend.load
load(1, 2)

For older Pythons you can put the class into a function:
>>class instantiate:
.... def __init__(self, *args):
.... self.args = args
.... def __call__(self, make_class):
.... return make_class()(*self.args)
....
>>class Backend:
.... @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
....
>>print Backend.load
load(1, 2)

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

Peter
Nov 1 '08 #3

P: n/a
>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.

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 <commandonward 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


Nov 1 '08 #4

P: n/a
On Nov 1, 8:13*am, Tim Chase <python.l...@tim.thechases.comwrote:
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
Nov 1 '08 #5

P: n/a
Tim Chase <py*********@tim.thechases.comwrites:
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:
>>class A(object):
.... def foo(self): return 'A.foo'
....
>>class b(instance(42), A):
.... def __init__(self, x): print 'This B is given ', x
.... def bar(self): return 'B.bar'
....
This B is given 42
>>b.foo()
'A.foo'
>>b.bar()
'B.bar'
>>>
(There may be a simpler way to do it, I've just adapted something else
to what you require)

--
Arnaud
Nov 1 '08 #6

P: n/a
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
Nov 1 '08 #7

P: n/a
Tim Chase <py*********@tim.thechases.comwrote:
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.
I think Martin v. Lwis expanded sufficiently on the idea of using
decorators, so I'll just point out one problem you may run into: the
pseudo-code you posted will create callable attributes on the class, but
unless you also implement the descriptor protocol they won't act like
methods. i.e. you won't get any reference to the instance on which you
called load/run/frob or whatever.

Of course the decorator solution has the opposite problem: you get a
reference to your Backend instance but not to the decorated function
itself. That probably shouldn't matter: what you wrote above looks to me
like you just do:

class DatabaseBackend:
@Action(...)
def load(self, options, args):
...

and the parse_args call is something done in the decorator rather than
repeated in each and every method that follows this pattern. Or even
better make the options parse to specific keyword arguments so you can
test an option directly inside the method rather than having to look it
up in a dictionary.

class DatabaseBackend:
@Action("load a thang into memory").
add_option("-f", "--file", help="load from file",
default=None).
add_option("--frobnify", help="frobnify the thang",
default=False, action="store_true")
def load(self, file, frobnify, args):
...

--
Duncan Booth http://kupuguy.blogspot.com
Nov 3 '08 #8

P: n/a
>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.
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


Nov 3 '08 #9

This discussion thread is closed

Replies have been disabled for this discussion.