From: Francesc A. <fa...@py...> - 2004-07-15 16:11:36
|
A Dijous 15 Juliol 2004 17:21, Colin J. Williams va escriure: > >What I propose is to be able to say: > >>>>r["c1"][1] > I would suggest going a step beyond this, so that one can have r.c1[1], > see the script below. Yeah. I've implemented something similar to access column elements for pytables Table objects. However, the problem in this case is that there are already attributes that "pollute" the column namespace, so that a column named "size" collides with the size() method. I came up with a solution by adding a new "cols" attribute to the Table object that is an instance of a simple class named Cols with no attributes that can pollute the namespace (except some starting by "__" or "_v_"). Then, it is just a matter of provide functionality to access the different columns. In that case, when a reference of a column is made, another object (instance of Column class) is returned. This Column object is basically an accessor to column values with a __getitem__() and __setitem__() methods. That might sound complicated, but it is not. I'm attaching part of the relevant code below. I personally like that solution in the context of pytables because it extends the "natural naming" convention quite naturally. A similar approach could be applied to RecArray objects as well, although numarray might (and probably do) have other usage conventions. > I have not explored the assignment of a value to r.c1.[1], but it seems > to be achievable. in the schema I've just proposed the next should be feasible: value = r.cols.c1[1] r.cols.c1[1] = value -- Francesc Alted ----------------------------------------------------------------- class Cols(object): """This is a container for columns in a table It provides methods to get Column objects that gives access to the data in the column. Like with Group instances and AttributeSet instances, the natural naming is used, i.e. you can access the columns on a table like if they were normal Cols attributes. Instance variables: _v_table -- The parent table instance _v_colnames -- List with all column names Methods: __getitem__(colname) """ def __init__(self, table): """Create the container to keep the column information. table -- The parent table """ self.__dict__["_v_table"] = table self.__dict__["_v_colnames"] = table.colnames # Put the column in the local dictionary for name in table.colnames: self.__dict__[name] = Column(table, name) def __len__(self): return self._v_table.nrows def __getitem__(self, name): """Get the column named "name" as an item.""" if not isinstance(name, types.StringType): raise TypeError, \ "Only strings are allowed as keys of a Cols instance. You passed object: %s" % name # If attribute does not exist, return None if not name in self._v_colnames: raise AttributeError, \ "Column name '%s' does not exist in table:\n'%s'" % (name, str(self._v_table)) return self.__dict__[name] def __str__(self): """The string representation for this object.""" # The pathname pathname = self._v_table._v_pathname # Get this class name classname = self.__class__.__name__ # The number of columns ncols = len(self._v_colnames) return "%s.cols (%s), %s columns" % (pathname, classname, ncols) def __repr__(self): """A detailed string representation for this object.""" out = str(self) + "\n" for name in self._v_colnames: # Get this class name classname = getattr(self, name).__class__.__name__ # The shape for this column shape = self._v_table.colshapes[name] # The type tcol = self._v_table.coltypes[name] if shape == 1: shape = (1,) out += " %s (%s%s, %s)" % (name, classname, shape, tcol) + "\n" return out class Column(object): """This is an accessor for the actual data in a table column Instance variables: table -- The parent table instance name -- The name of the associated column Methods: __getitem__(key) """ def __init__(self, table, name): """Create the container to keep the column information. table -- The parent table instance name -- The name of the column that is associated with this object """ self.table = table self.name = name # Check whether an index exists or not iname = "_i_"+table.name+"_"+name self.index = None if iname in table._v_parent._v_indices: self.index = Index(where=self, name=iname, expectedrows=table._v_expectedrows) else: self.index = None def __getitem__(self, key): """Returns a column element or slice It takes different actions depending on the type of the "key" parameter: If "key" is an integer, the corresponding element in the column is returned as a NumArray/CharArray, or a scalar object, depending on its shape. If "key" is a slice, the row slice determined by this slice is returned as a NumArray or CharArray object (whatever is appropriate). """ if isinstance(key, types.IntType): if key < 0: # To support negative values key += self.table.nrows (start, stop, step) = processRange(self.table.nrows, key, key+1, 1) return self.table._read(start, stop, step, self.name, None)[0] elif isinstance(key, types.SliceType): (start, stop, step) = processRange(self.table.nrows, key.start, key.stop, key.step) return self.table._read(start, stop, step, self.name, None) else: raise TypeError, "'%s' key type is not valid in this context" % \ (key) def __str__(self): """The string representation for this object.""" # The pathname pathname = self.table._v_pathname # Get this class name classname = self.__class__.__name__ # The shape for this column shape = self.table.colshapes[self.name] if shape == 1: shape = (1,) # The type tcol = self.table.coltypes[self.name] return "%s.cols.%s (%s%s, %s)" % (pathname, self.name, classname, shape, tcol) def __repr__(self): """A detailed string representation for this object.""" return str(self) |