overloading *something

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • James Stroud

    overloading *something

    Hello All,

    How does one make an arbitrary class (e.g. class myclass(object) ) behave like
    a list in method calls with the "*something " operator? What I mean is:

    myobj = myclass()

    doit(*myobj)

    I've looked at getitem, getslice, and iter. What is it if not one of these?

    And, how about the "**somethin g" operator?

    James

    --
    James Stroud
    UCLA-DOE Institute for Genomics and Proteomics
    Box 951570
    Los Angeles, CA 90095


  • Ron Adam

    #2
    Re: overloading *something



    James Stroud wrote:
    [color=blue]
    > Hello All,
    >
    > How does one make an arbitrary class (e.g. class myclass(object) ) behave like
    > a list in method calls with the "*something " operator? What I mean is:[/color]

    You need to base myclass on a list if I understand your question.

    class myclass(list):
    def __init__(self, *items):
    # change items if needed
    # initate other attributes if needed
    list.__init__(s elf, *items)

    Then the line below should work. Of course it won't do much with out
    something in it. ;-)
    [color=blue]
    > myobj = myclass()
    >
    > doit(*myobj)
    >
    > I've looked at getitem, getslice, and iter. What is it if not one of these?
    >
    > And, how about the "**somethin g" operator?
    >
    > James[/color]

    A dictionary would be pretty much the same except subclassed from a
    dictionary of course.

    Cheers,
    Ron



    Comment

    • Alex Martelli

      #3
      Re: overloading *something

      Ron Adam <rrr@ronadam.co m> wrote:
      [color=blue]
      > James Stroud wrote:
      >[color=green]
      > > Hello All,
      > >
      > > How does one make an arbitrary class (e.g. class myclass(object) ) behave
      > > like a list in method calls with the "*something " operator? What I mean
      > > is:[/color]
      >
      > You need to base myclass on a list if I understand your question.[/color]

      Not necessary, all you need is __iter__:
      [color=blue][color=green][color=darkred]
      >>> def f(*a): print a[/color][/color][/color]
      ....[color=blue][color=green][color=darkred]
      >>> class X(object):[/color][/color][/color]
      .... def __iter__(self): return iter(xrange(4))
      ....[color=blue][color=green][color=darkred]
      >>> f(*X())[/color][/color][/color]
      (0, 1, 2, 3)[color=blue][color=green][color=darkred]
      >>>[/color][/color][/color]
      [color=blue][color=green]
      > > I've looked at getitem, getslice, and iter. What is it if not one of these?[/color][/color]

      Obviously James hadn't looked at __iter__ in the RIGHT way!

      [color=blue][color=green]
      > > And, how about the "**somethin g" operator?
      > >
      > > James[/color]
      >
      > A dictionary would be pretty much the same except subclassed from a
      > dictionary of course.[/color]

      I believe this one is correct (but I have not checked in-depth!).


      Alex

      Comment

      • Leif K-Brooks

        #4
        Re: overloading *something

        James Stroud wrote:[color=blue]
        > Hello All,
        >
        > How does one make an arbitrary class (e.g. class myclass(object) ) behave like
        > a list in method calls with the "*something " operator? What I mean is:
        >
        > myobj = myclass()
        >
        > doit(*myobj)[/color]

        Make it iterable:
        [color=blue][color=green][color=darkred]
        >>> class Foo(object):[/color][/color][/color]
        ... def __iter__(self):
        ... yield 1
        ... yield 2
        ... yield 3
        ...[color=blue][color=green][color=darkred]
        >>> def bar(*args):[/color][/color][/color]
        ... print args
        ...[color=blue][color=green][color=darkred]
        >>> bar(*Foo())[/color][/color][/color]
        (1, 2, 3)

        [color=blue]
        > And, how about the "**somethin g" operator?[/color]

        Use a dictionary.

        Comment

        • Ron Adam

          #5
          Re: overloading *something



          Alex Martelli wrote:[color=blue]
          > Ron Adam <rrr@ronadam.co m> wrote:
          >
          >[color=green]
          >>James Stroud wrote:[/color][/color]
          [color=blue][color=green][color=darkred]
          >>>And, how about the "**somethin g" operator?
          >>>
          >>>James[/color]
          >>
          >>A dictionary would be pretty much the same except subclassed from a
          >>dictionary of course.[/color]
          >
          >
          > I believe this one is correct (but I have not checked in-depth!).
          >
          >
          > Alex[/color]

          A quick test shows the error message to be very specific in this case,
          where as the *something error message requests a more general sequence.

          [color=blue][color=green][color=darkred]
          >>> def foo(**b): pass[/color][/color][/color]
          ....[color=blue][color=green][color=darkred]
          >>> class a: pass[/color][/color][/color]
          ....[color=blue][color=green][color=darkred]
          >>> foo(**a)[/color][/color][/color]
          Traceback (most recent call last):
          File "<stdin>", line 1, in ?
          TypeError: foo() argument after ** must be a dictionary


          Ron

          Comment

          • James Stroud

            #6
            Re: overloading *something

            On Monday 07 November 2005 20:36, Alex Martelli wrote:[color=blue][color=green][color=darkred]
            > > > I've looked at getitem, getslice, and iter. What is it if not one of
            > > > these?[/color][/color]
            >
            > Obviously James hadn't looked at __iter__ in the RIGHT way![/color]

            I was attempting to re-define iter of a subclassed list, to find the "magic"
            method, but it didn't work. I'm not sure if "wrong" and "right" apply here:

            py> class NewList(list):
            .... def __iter__(self):
            .... return iter([8,9,10])
            ....
            py>
            py> n = NewList([1,2,3])
            py>
            py> def doit(*args):
            .... print args
            ....
            py> doit(*n)
            (1, 2, 3)
            py> for x in iter(n):
            .... print x
            ....
            8
            9
            10


            --
            James Stroud
            UCLA-DOE Institute for Genomics and Proteomics
            Box 951570
            Los Angeles, CA 90095


            Comment

            • Peter Otten

              #7
              Re: overloading *something

              James Stroud wrote:
              [color=blue]
              > I was attempting to re-define iter of a subclassed list, to find the
              > "magic" method, but it didn't work.[/color]
              [color=blue][color=green][color=darkred]
              >>> class List(list):[/color][/color][/color]
              .... def __iter__(self): return iter("abc")
              ....[color=blue][color=green][color=darkred]
              >>> a = List([1,2,3])
              >>> list(a)[/color][/color][/color]
              ['a', 'b', 'c'][color=blue][color=green][color=darkred]
              >>> tuple(a)[/color][/color][/color]
              (1, 2, 3)

              list-to-tuple conversion is optimized for performance -- basically a
              memcopy() of the internal data. As with a similar peculiarity with
              file.write() and the print statement, the problem could be shunned if
              python would check for the exact class instead of a test that is equivalent
              to isinstance().

              Peter

              Comment

              • James Stroud

                #8
                Re: overloading *something

                On Monday 07 November 2005 20:36, Alex Martelli wrote:[color=blue]
                > Ron Adam <rrr@ronadam.co m> wrote:[color=green]
                > > James Stroud wrote:[color=darkred]
                > > > Hello All,
                > > >
                > > > How does one make an arbitrary class (e.g. class myclass(object) )
                > > > behave like a list in method calls with the "*something " operator? What
                > > > I mean is:[/color][/color][/color]
                [snip][color=blue][color=green]
                > > A dictionary would be pretty much the same except subclassed from a
                > > dictionary of course.[/color]
                >
                > I believe this one is correct (but I have not checked in-depth!).[/color]

                Does anyone else find the following annoying:


                py> from UserDict import UserDict
                py> aud = UserDict({"a":1 , "b":2})
                py> def doit(**kwargs):
                .... print kwargs
                ....
                py> aud
                {'a': 1, 'b': 2}
                py> doit(**aud)
                Traceback (most recent call last):
                File "<stdin>", line 1, in ?
                TypeError: doit() argument after ** must be a dictionary


                UserDict should be isomorphic with a dict. The fact that it is not in this
                case seems terribly un-pythonic to me.

                --
                James Stroud
                UCLA-DOE Institute for Genomics and Proteomics
                Box 951570
                Los Angeles, CA 90095


                Comment

                • Robert Kern

                  #9
                  Re: overloading *something

                  James Stroud wrote:
                  [color=blue]
                  > Does anyone else find the following annoying:
                  >
                  > py> from UserDict import UserDict
                  > py> aud = UserDict({"a":1 , "b":2})
                  > py> def doit(**kwargs):
                  > ... print kwargs
                  > ...
                  > py> aud
                  > {'a': 1, 'b': 2}
                  > py> doit(**aud)
                  > Traceback (most recent call last):
                  > File "<stdin>", line 1, in ?
                  > TypeError: doit() argument after ** must be a dictionary
                  >
                  > UserDict should be isomorphic with a dict. The fact that it is not in this
                  > case seems terribly un-pythonic to me.[/color]

                  UserDict only exists for backwards compatibility with old code that used
                  it before one could subclass from dict directly. Don't use it if you can
                  avoid it. UserDict only ever exposed the Python-side interface of dicts.
                  It couldn't expose the C-side interface, and it's the C-side interface
                  that **kwds is using.

                  --
                  Robert Kern
                  rkern@ucsd.edu

                  "In the fields of hell where the grass grows high
                  Are the graves of dreams allowed to die."
                  -- Richard Harter

                  Comment

                  • James Stroud

                    #10
                    Re: overloading *something

                    On Tuesday 08 November 2005 22:54, Robert Kern wrote:[color=blue]
                    > James Stroud wrote:[color=green]
                    > > Does anyone else find the following annoying:
                    > >
                    > > py> from UserDict import UserDict
                    > > py> aud = UserDict({"a":1 , "b":2})
                    > > py> def doit(**kwargs):
                    > > ... print kwargs
                    > > ...
                    > > py> aud
                    > > {'a': 1, 'b': 2}
                    > > py> doit(**aud)
                    > > Traceback (most recent call last):
                    > > File "<stdin>", line 1, in ?
                    > > TypeError: doit() argument after ** must be a dictionary
                    > >
                    > > UserDict should be isomorphic with a dict. The fact that it is not in
                    > > this case seems terribly un-pythonic to me.[/color]
                    >
                    > UserDict only exists for backwards compatibility with old code that used
                    > it before one could subclass from dict directly. Don't use it if you can
                    > avoid it. UserDict only ever exposed the Python-side interface of dicts.
                    > It couldn't expose the C-side interface, and it's the C-side interface
                    > that **kwds is using.[/color]

                    That **kwargs insists on using the C-side interface is precisely the annoyance
                    to which I am referring. I should be able to write a dictionary-like
                    interface in python and **kwargs should in turn be able to use it. If the
                    retort is that the C-side interface is used for performance, my retort to the
                    retort is that an isinstance() is already being called somewhere, so no
                    additional tests would need to be made to make **kwargs more generalized.

                    James

                    --
                    James Stroud
                    UCLA-DOE Institute for Genomics and Proteomics
                    Box 951570
                    Los Angeles, CA 90095


                    Comment

                    • sjdevnull@yahoo.com

                      #11
                      Re: overloading *something

                      Robert Kern wrote:[color=blue]
                      > James Stroud wrote:
                      >[color=green]
                      > > Does anyone else find the following annoying:
                      > >
                      > > py> from UserDict import UserDict
                      > > py> aud = UserDict({"a":1 , "b":2})
                      > > py> def doit(**kwargs):
                      > > ... print kwargs[/color]
                      >
                      > UserDict only exists for backwards compatibility with old code that used
                      > it before one could subclass from dict directly. Don't use it if you can
                      > avoid it. UserDict only ever exposed the Python-side interface of dicts.
                      > It couldn't expose the C-side interface, and it's the C-side interface
                      > that **kwds is using.[/color]

                      Which means that you can't subclass dict with, say, a lazy dictionary
                      (that doesn't retrieve values until they're looked up) and use it with
                      **kwargs. That bit me last year:



                      It would be useful in some situations to be able to do this (especially
                      where getting the dictionary values is time-consuming and the function
                      you're calling doesn't use all the values in the dictionary). For my
                      particular case I had a fairly easy workaround.

                      Comment

                      • Robert Kern

                        #12
                        Re: overloading *something

                        James Stroud wrote:
                        [color=blue]
                        > That **kwargs insists on using the C-side interface is precisely the annoyance
                        > to which I am referring. I should be able to write a dictionary-like
                        > interface in python and **kwargs should in turn be able to use it. If the
                        > retort is that the C-side interface is used for performance, my retort to the
                        > retort is that an isinstance() is already being called somewhere, so no
                        > additional tests would need to be made to make **kwargs more generalized.[/color]

                        Well, the test is in Python/ceval.c (grep for the error message) and the
                        function that needs a bona fide dictionary is PyObject_Call in
                        Objects/abstract.c . If you can work up a patch, Guido will probably
                        consider it although I would suggest searching python-dev for previous
                        discussions first.

                        --
                        Robert Kern
                        rkern@ucsd.edu

                        "In the fields of hell where the grass grows high
                        Are the graves of dreams allowed to die."
                        -- Richard Harter

                        Comment

                        Working...