Simplifying anonymous inner classes?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tim Chase

    Simplifying anonymous inner classes?

    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.




  • Duncan Booth

    #2
    Re: Simplifying anonymous inner classes?

    Tim Chase <python.list@ti m.thechases.com wrote:
    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?

    Comment

    • Peter Otten

      #3
      Re: Simplifying anonymous inner classes?

      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(obj ect):
      .... def __init__(self, *args):
      .... self.args = args
      .... def __call__(self, class_):
      .... return class_(*self.ar gs)
      ....
      >>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()(*s elf.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

      Comment

      • Tim Chase

        #4
        Re: Simplifying anonymous inner classes?

        >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 <commandonwar d 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.Option Parser(...)
        def __call__(self, argv): # argv is a list like sys.argv
        options, args = self.parser.par se_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




        Comment

        • Carl Banks

          #5
          Re: Simplifying anonymous inner classes?

          On Nov 1, 8:13 am, Tim Chase <python.l...@ti m.thechases.com 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(...)
          >
          [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_instantiat e(name,bases,cl sdict):
          cls = type.__new__(ty pe,name+"_type" ,
          bases,clsdict)
          obj = cls()
          return obj

          class load(Action):
          __metaclass__ = self_instantiat e
          ....



          Carl Banks

          Comment

          • Arnaud Delobelle

            #6
            Re: Simplifying anonymous inner classes?

            Tim Chase <python.list@ti m.thechases.com writes:
            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(ty pe):
            pass

            class Instance(object ):
            __metaclass__ = MetaInstance

            @staticmethod
            def MetaInstance__n ew__(meta, name, bases, attrs):
            bases = list(bases)
            bases.remove(In stance)
            cls = type(name.capit alize(), tuple(bases), attrs)
            return cls(*args, **kwargs)

            MetaInstance.__ new__ = MetaInstance__n ew__

            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

            Comment

            • =?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

              #7
              Re: Simplifying anonymous inner classes?

              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

              Comment

              • Duncan Booth

                #8
                Re: Simplifying anonymous inner classes?

                Tim Chase <python.list@ti m.thechases.com wrote:
                def __init__(self, ...):
                self.parser = optparse.Option Parser(...)
                def __call__(self, argv): # argv is a list like sys.argv
                options, args = self.parser.par se_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. Löwis 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_t rue")
                def load(self, file, frobnify, args):
                ...

                --
                Duncan Booth http://kupuguy.blogspot.com

                Comment

                • Tim Chase

                  #9
                  Re: Simplifying anonymous inner classes?

                  >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 "pythonicit y". Until such time as Python offers
                  anonymous classes natively :)

                  Thanks to all who offered suggestions.

                  -tkc




                  Comment

                  Working...