overloading *something

Discussion in 'Python' started by James Stroud, Nov 8, 2005.

  1. James Stroud

    James Stroud Guest

    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 "**something" operator?

    James

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

    http://www.jamesstroud.com/
     
    James Stroud, Nov 8, 2005
    #1
    1. Advertising

  2. James Stroud

    Ron Adam Guest

    James Stroud wrote:

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


    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__(self, *items)

    Then the line below should work. Of course it won't do much with out
    something in it. ;-)

    > myobj = myclass()
    >
    > doit(*myobj)
    >
    > I've looked at getitem, getslice, and iter. What is it if not one of these?
    >
    > And, how about the "**something" operator?
    >
    > James


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

    Cheers,
    Ron
     
    Ron Adam, Nov 8, 2005
    #2
    1. Advertising

  3. Ron Adam <> wrote:

    > James Stroud wrote:
    >
    > > 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:

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


    Not necessary, all you need is __iter__:

    >>> def f(*a): print a

    ....
    >>> class X(object):

    .... def __iter__(self): return iter(xrange(4))
    ....
    >>> f(*X())

    (0, 1, 2, 3)
    >>>


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


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


    > > And, how about the "**something" operator?
    > >
    > > James

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


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


    Alex
     
    Alex Martelli, Nov 8, 2005
    #3
  4. James Stroud wrote:
    > 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)


    Make it iterable:

    >>> class Foo(object):

    ... def __iter__(self):
    ... yield 1
    ... yield 2
    ... yield 3
    ...
    >>> def bar(*args):

    ... print args
    ...
    >>> bar(*Foo())

    (1, 2, 3)


    > And, how about the "**something" operator?


    Use a dictionary.
     
    Leif K-Brooks, Nov 8, 2005
    #4
  5. James Stroud

    Ron Adam Guest

    Alex Martelli wrote:
    > Ron Adam <> wrote:
    >
    >
    >>James Stroud wrote:


    >>>And, how about the "**something" operator?
    >>>
    >>>James

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

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


    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.


    >>> def foo(**b): pass

    ....
    >>> class a: pass

    ....
    >>> foo(**a)

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    TypeError: foo() argument after ** must be a dictionary


    Ron
     
    Ron Adam, Nov 8, 2005
    #5
  6. James Stroud

    James Stroud Guest

    On Monday 07 November 2005 20:36, Alex Martelli wrote:
    > > > I've looked at getitem, getslice, and iter. What is it if not one of
    > > > these?

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


    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

    http://www.jamesstroud.com/
     
    James Stroud, Nov 8, 2005
    #6
  7. James Stroud

    Peter Otten Guest

    James Stroud wrote:

    > I was attempting to re-define iter of a subclassed list, to find the
    > "magic" method, but it didn't work.


    >>> class List(list):

    .... def __iter__(self): return iter("abc")
    ....
    >>> a = List([1,2,3])
    >>> list(a)

    ['a', 'b', 'c']
    >>> tuple(a)

    (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
     
    Peter Otten, Nov 8, 2005
    #7
  8. James Stroud

    James Stroud Guest

    On Monday 07 November 2005 20:36, Alex Martelli wrote:
    > Ron Adam <> wrote:
    > > James Stroud wrote:
    > > > 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:

    [snip]
    > > A dictionary would be pretty much the same except subclassed from a
    > > dictionary of course.

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


    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

    http://www.jamesstroud.com/
     
    James Stroud, Nov 9, 2005
    #8
  9. James Stroud

    Robert Kern Guest

    James Stroud wrote:

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


    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


    "In the fields of hell where the grass grows high
    Are the graves of dreams allowed to die."
    -- Richard Harter
     
    Robert Kern, Nov 9, 2005
    #9
  10. James Stroud

    James Stroud Guest

    On Tuesday 08 November 2005 22:54, Robert Kern wrote:
    > James Stroud wrote:
    > > 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.

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


    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

    http://www.jamesstroud.com/
     
    James Stroud, Nov 9, 2005
    #10
  11. James Stroud

    Guest

    Robert Kern wrote:
    > James Stroud wrote:
    >
    > > 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

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


    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:

    http://groups.google.com/group/comp.lang.python/browse_frm/thread/95cfa91b732cd482/24b7e17bb395494e

    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.
     
    , Nov 9, 2005
    #11
  12. James Stroud

    Robert Kern Guest

    James Stroud wrote:

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


    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


    "In the fields of hell where the grass grows high
    Are the graves of dreams allowed to die."
    -- Richard Harter
     
    Robert Kern, Nov 9, 2005
    #12
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Iyer, Prasad C

    Overloading __init__ & Function overloading

    Iyer, Prasad C, Sep 30, 2005, in forum: Python
    Replies:
    3
    Views:
    6,438
    Fredrik Lundh
    Sep 30, 2005
  2. Fredrik Lundh
    Replies:
    0
    Views:
    466
    Fredrik Lundh
    Sep 30, 2005
  3. Steve Holden
    Replies:
    0
    Views:
    447
    Steve Holden
    Sep 30, 2005
  4. Iyer, Prasad C
    Replies:
    4
    Views:
    596
    John J. Lee
    Sep 30, 2005
  5. Fredrik Lundh
    Replies:
    0
    Views:
    414
    Fredrik Lundh
    Sep 30, 2005
Loading...

Share This Page