[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