overloading *something

J

James Stroud

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/
 
R

Ron Adam

James said:
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
 
A

Alex Martelli

Ron Adam said:
You need to base myclass on a list if I understand your question.

Not necessary, all you need is __iter__:
.... def __iter__(self): return iter(xrange(4))
....
Obviously James hadn't looked at __iter__ in the RIGHT way!

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
 
L

Leif K-Brooks

James said:
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:
... def __iter__(self):
... yield 1
... yield 2
... yield 3
... ... print args
... (1, 2, 3)

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

Use a dictionary.
 
R

Ron Adam

Alex said:
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.

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


Ron
 
J

James Stroud

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/
 
P

Peter Otten

James said:
I was attempting to re-define iter of a subclassed list, to find the
"magic" method, but it didn't work.
.... 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
 
J

James Stroud

Ron Adam said:
James said:
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/
 
R

Robert Kern

James said:
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
(e-mail address removed)

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

James Stroud

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/
 
S

sjdevnull

Robert said:
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.
 
R

Robert Kern

James said:
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
(e-mail address removed)

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

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,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top