Namedtuples: some unexpected inconveniences

Deborah Swanson python at deborahswanson.net
Thu Apr 13 20:41:12 EDT 2017


Peter Otten wrote, on Thursday, April 13, 2017 12:17 AM
> 
> Deborah Swanson wrote:
> 
> > Peter Otten wrote, on Wednesday, April 12, 2017 11:35 PM
> >> 
> >> Deborah Swanson wrote:
> >> 
> >> > It's a small point, but I suspect getattr(record, label)
> >> would still
> >> > fail, even if label's value is 'label' and only 'label', 
> but what's 
> >> > the point of having a variable if it will only ever have 
> just one 
> >> > value?
> >> 
> >> You are misunderstanding. Your getattr() call fails because you
have
> >> 
> >> label = "label"
> >> 
> >> burried somewhere in your code. As soon as you change that to
> >> 
> >> label = <insert an existing attribute name here>
> >> 
> >> the error will go away.
> > 
> > 
> > Yes, the error goes away, but now getattr(record, label) is useless 
> > for processing field names, unless you want to write a line of code 
> > for each one. (I have 17 field names, and forget about passing label

> > to a function.)

Uh-oh, I boobooed and misread what you wrote here. 

> No, it's not useless:
> 
> >>> from collections import namedtuple
> >>> T = namedtuple("T", "foo bar baz")
> >>> t = T(1, 2, 3)
> >>> for name in t._fields:
> ...     print(name, "=", getattr(t, name))
> ... 
> foo = 1
> bar = 2
> baz = 3

Wow. Ok, I can see that the specific circumstance I got the "object has
no attribute 'label' error was quite likely not due to using getattr()
with a variable for a namedtuple field name, and probably some other
factor was at work.

Unfortunately, when I shifted gears on the overall problem and abandoned
the strategy of making the group-by defaultdict, I renamed the project
file and started over, going back to the original list of namedtuples.
As a result, all the back versions of my code producing this error were
lost.

I've spent the better part of today rewriting the lost code, and I'm
nowhere near finished, and now my illness is ganging up on me again. So
anything further will have to wait til tomorrow.

I remain quite sure that at no point did I have the line

label = "label"

in my code, and I wouldn't even have thought of writing it because it's
so absurd in so many ways. Hopefully I can show you what I wrote soon,
and you can see for yourself.

> And as a special service here's a mutable datatype with sufficient 
> namedtuple compatibility to replicate the above snippet:
> 
> $ cat namedtuple_replacement.py
> def struct(name, wanted_columns):
>     class Struct:
>         _fields = __slots__ = wanted_columns.split()
> 
>         def __init__(self, *args):
>             names = self.__slots__
>             if len(args) != len(names):
>                 raise ValueError
>             for name, value in zip(names, args):
>                 setattr(self, name, value)
> 
>         @classmethod
>         def _make(cls, args):
>             return cls(*args)
> 
>         def __repr__(self):
>             names = self.__slots__
>             return "{}({})".format(
>                 self.__class__.__name__,
>                 ", ".join("{}={!r}".format(n, getattr(self, 
> n)) for n in 
> names)
>             )
> 
>     Struct.__name__ = name
>     return Struct
> 
> T = struct("T", "foo bar baz")
> t = T(1, 2, 3)
> print(t)
> for name in t._fields:
>     print(name, "=", getattr(t, name))
> t.bar = 42
> print(t)
> $ python3 namedtuple_replacement.py 
> T(foo=1, bar=2, baz=3)
> foo = 1
> bar = 2
> baz = 3
> T(foo=1, bar=42, baz=3)

Thank you for this datatype definition.

I won't take a serious look at it until I rewrite the code I lost and
get to the bottom of why getattr() got the attribute error, but once
that issue is resolved I will return to your mutable datatype with
namedtuple 
compatibility (to some extent, I gather).

I apologize for the delay, but your simple getattr() example above
demands that I find out why it wasn't working for me before moving on
with the rest of this. And that will take some time. Probably not the 3
weeks it took me to get to the point where I was consistently seeing the
error, but it will be awhile. I'll come back to address these issues and
your datatype when I've got code to show what I did. (For my own sanity,
if no other reason.)



More information about the Python-list mailing list