[Tutor] question about descriptors
Albert-Jan Roskam
sjeik_appie at hotmail.com
Wed Nov 11 03:08:46 EST 2015
<snip>
> I think the basic misunderstandings are that
>
> (1) the __get__() method has to be implemented by the descriptor class
> (2) the descriptor instances should be attributes of the class that is
> supposed to invoke __get__(). E. g.:
>
> class C(object):
> x = decriptor()
>
> c = C()
>
> c.x # invoke c.x.__get__(c, C) under the hood.
Exactly right, that was indeed my misunderstanding! I was thinking about __get__ and __set__ in the same terms as e.g. __getitem__ and __setitem__
> As a consequence you need one class per set of attributes, instantiating the
> same AttrAccess for csv files with differing layouts won't work.
That is no problem at all for me. One instance per file will be fine.
> Here's how to do it all by yourself:
>
> class ReadColumn(object):
> def __init__(self, index):
> self._index = index
> def __get__(self, obj, type=None):
> return obj._row[self._index]
> def __set__(self, obj, value):
> raise AttributeError("oops")
This appears to return one value, whereas I wanted I wanted to return all values of a column, ie as many values as there are rows.
But the logic probably won't change. Same applies to the use of namedtuple, I suppose (?). I have never used namedtuple like namedtuple("Column", self.header)(*self.columns).
> def first_row(instream):
> reader = csv.reader(instream, delimiter=";")
>
> class Row(object):
> def __init__(self, row):
> self._row = row
>
> for i, header in enumerate(next(reader)):
> setattr(Row, header, ReadColumn(i))
>
> return Row(next(reader))
>
>
> f = StringIO("a;b;c\n1;2;3\n4;5;6\n7;8;9\n")
> row = first_row(f)
> print row.a
> row.a = 42
>
> Instead of a custom descriptor you can of course use the built-in property:
>
> for i, header in enumerate(next(reader)):
> setattr(Row, header, property(lambda self, i=i: self._row[i]))
This seems most attractive/straightforward to me.
> In many cases you don't care about the specifics of the row class and use
> collections.namedtuple:
>
>
> def rows(instream):
> reader = csv.reader(instream, delimiter=";")
> Row = collections.namedtuple("Row", next(reader))
> return itertools.imap(Row._make, reader)
>
>
> f = StringIO("a;b;c\n1;2;3\n4;5;6\n7;8;9\n")
> row = next(rows(f))
> print row.a
> row.a = 42
Thanks a lot for helping me!
More information about the Tutor
mailing list