question on namedtuple

H

hetchkay

Hi,
For purposes I don't want to go into here, I have the following code:
def handleObj(obj):
if isinstance(obj, MyType):
return obj.handle()
elif isinstance(obj, (list, tuple, set)):
return obj.__class__(map (handleObj, obj))
elif isinstance(obj, dict):
return obj.__class__((handleObj(k), handleObj(v)) for k, v in
obj.items())
else:
return obj

This works fine except if obj is a namedtuple. A namedtuple object has
different constructor signature from tuple:
tuple([1,2]) (1,2)
collections.namedtuple("sample", "a, b")([1, 2])
Traceback (most recent call last):
sample(a=1, b=2)

Is there any easy way of knowing that the obj is a namedtuple and not
a plain tuple [so that I could use obj.__class__(*map(handleObj, obj))
instead of obj.__class__(map(handleObj, obj)) ].

Thanks in advance for your help.

Krishnan
 
C

Chris Rebert

Hi,
For purposes I don't want to go into here, I have the following code:
def handleObj(obj):
 if isinstance(obj, MyType):
    return obj.handle()
 elif isinstance(obj, (list, tuple, set)):
    return obj.__class__(map (handleObj, obj))
 elif isinstance(obj, dict):
    return obj.__class__((handleObj(k), handleObj(v)) for k, v in
obj.items())
 else:
    return obj

This works fine except if obj is a namedtuple. A namedtuple object has
different constructor signature from tuple:
tuple([1,2]) (1,2)
collections.namedtuple("sample", "a, b")([1, 2])
Traceback (most recent call last):
sample(a=1, b=2)

Is there any easy way of knowing that the obj is a namedtuple and not
a plain tuple [so that I could use obj.__class__(*map(handleObj, obj))
instead of obj.__class__(map(handleObj, obj)) ].

It's very slightly brittle, but a good heuristic is probably:

if isinstance(obj, tuple) and all(hasattr(obj, attr_name) for \
attr_name in ('_make','_fields','_replace','_asdict')):
return obj.__class__(*map(handleObj, obj))

I couldn't find/think of a more direct/reliable method. Though perhaps
there's some more obscure but accurate method.

Cheers,
Chris
 
P

Peter Otten

hetchkay said:
For purposes I don't want to go into here, I have the following code:
def handleObj(obj):
if isinstance(obj, MyType):
return obj.handle()
elif isinstance(obj, (list, tuple, set)):
return obj.__class__(map (handleObj, obj))
elif isinstance(obj, dict):
return obj.__class__((handleObj(k), handleObj(v)) for k, v in
obj.items())
else:
return obj

This works fine except if obj is a namedtuple. A namedtuple object has
different constructor signature from tuple:
tuple([1,2]) (1,2)
collections.namedtuple("sample", "a, b")([1, 2])
Traceback (most recent call last):
sample(a=1, b=2)

Is there any easy way of knowing that the obj is a namedtuple and not
a plain tuple [so that I could use obj.__class__(*map(handleObj, obj))
instead of obj.__class__(map(handleObj, obj)) ].

I don't think there is a safe way to do this short of a comprehensive list
of namedtuple classes. In practice it may be sufficient to check the duck
type of the tuple subclass, e. g.:

elif isinstance(obj, (list, set)):
return obj.__class__(map(handleObj, obj))
elif isinstance(obj, tuple):
try:
make = obj._make
except AttributeError:
make = obj.__class__
return make(handleObj(item) for item in obj)

Peter
 

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,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top