Reputation: 4570
The code below works (it will eventually pull records from a database via SQL), but I am having trouble understanding why the assert
statement in the code below works.
def build_row(table, cols):
"""Build a class that creates instances of specific rows"""
class DataRow:
"""Generic data row class, specialized by surrounding function"""
def __init__(self, data):
"""Uses data and column names to inject attributes"""
assert len(data)==len(self.cols)
for colname, dat in zip(self.cols, data):
setattr(self, colname, dat)
def __repr__(self):
return "{0}_record({1})".format(self.table, ", ".join(["{0!r}".format(getattr(self, c)) for c in self.cols]))
DataRow.table = table
DataRow.cols = cols.split()
return DataRow
When is the length of 'data' determined and how is it guaranteed to be the same length as 'self.cols'? Will someone please explain this behavior?
Upvotes: 0
Views: 2638
Reputation: 63782
This may make more sense to you if you replace the references to self.cols
and self.table
with self.__class__.cols
and self.__class__.table
. This confusion is caused by accessing class attributes through the self
object as if they were instance attributes, and why I don't particularly like this coding idiom. When looking at the code in __init__
, where instance attributes are typically assigned their values, it is jarring to immediately see a statement that reads the value of self.cols
- where the heck did self.cols
get initialized?! On the other hand, if you change this assert to:
assert len(data)==len(self.__class__.cols)
then it becomes clearer that the list of data values is expected to be the same length as the defined list of columns for this instance of DataRow. The class attribute cols
gets initialized right after the class definition, in this statement:
DataRow.cols = cols.split()
long before any instance gets created - that's why this assert works.
The writer of this code might consider converting to the more current namedtuple
construct.
Upvotes: 1
Reputation: 33407
When you defined DataRow
, the column names are set in the variable self.cols
. So, when you're instantiating the class, you're supposed to fill every column.
That's why you need both lists having the same length. Otherwise you may not have all attributes.
The way it's done is by setting an attribute with the name of the column which isn't be the best option because if you have a column named cols
or table
or even __repr__
, it may break your code.
Upvotes: 0
Reputation: 799510
data
is given a value when you instantiate the class returned by the build_row()
function.
It is not guaranteed to be the same length as self.cols
; perhaps you never instantiate the class, and so never see an error.
Upvotes: 1