Edited by Martin Thomas Humby, Wednesday, 31 Oct 2018, 23:07
There is a simple and perhaps obvious relationship between a class of objects, a database table and the table represented as a two dimensional array in a programming language: the class is the table and every instance of the class forms a row in that table. Using Python class to array conversion is equally simple.
Basic Python does not provide multi-dimensional arrays in the C / pascal static-array sense but goes straight to the more flexible but less computationally efficient lists of lists. The Numpy extension does support these types directly so, to keep things simple, it is convenient to use Numpy. A two dimensional can be declared as follows:
The numpy.ndarray returned by this call displays itself as
array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
np.array() iterates the Python list of lists to get this result.
Another extension, Pandas, built on Numpy, moves closer to a database table by supplying an index of column names and an index of rows:
import pandas as pd series3 = pd.DataFrame(array, columns=['from_1', 'from_2', 'from_3'])
To allow a list of objects to be converted to a Numpy array or Pandas DataFrame, objects need an __iter__() method that returns each desired attribute of the object replacing the sublists in the abpve example. Optionally a __str__() method to supply a string representation when an instance is seen in a column and a class method columns() that returns a list of column names can also be provided:
class Person: def __init__(self, name, age, notes): self.name = name self.age = age self.notes = notes 900 def __iter__(self): yield self yield self.name yield self.age yield self.notes
people = Struct() people.add_to_facet(Person('Jim', 42, 'The time has come for all good men to come to the aid of the party')) people.add_to_facet(Person('Jane', 24, 'She sells sea shells on the sea shore')) people.add_to_facet(Person('Jill', 17, 'The quick brown fox jumps over the lazy dog')) print(people.items)
Items are objects:
df = people.items
obj = df.Items[0]
print(obj.hello())
"Hello! I'm Jill. The quick brown fox jumps over the lazy dog"
So, that is a basic structure with one facet. In a real application with multiple facets represented by multiple dictionaries it may be useful to be able to select the object attributes returned to build a table on the fly:
# modify the DataFrame columns returned by observations def observations_columns(self, *fields, columns=0): self._observations_df = None s = 'def f(self):pass' for fld in fields: if fld == 'observation' or fld == '' or fld == 'self': s += ';yield self' else: s += ';yield self.' + fld s += '\nObservation.__iter__=f' exec(s) if columns != 0: # allow for None columns Observation._cols = columns else: names = list(f) for i, name in enumerate(names): names[i] = names[i].replace('.', '_') Observation._cols = names
Without the complications from joining tables, intermediate tables to represent variable content fields or combining documents, the power of OOP allows attributes to be selected from the immediate object or from other objects referenced from it down to any level.
Python 1: How to use a class as a table
There is a simple and perhaps obvious relationship between a class of objects, a database table and the table represented as a two dimensional array in a programming language: the class is the table and every instance of the class forms a row in that table. Using Python class to array conversion is equally simple.
Basic Python does not provide multi-dimensional arrays in the C / pascal static-array sense but goes straight to the more flexible but less computationally efficient lists of lists. The Numpy extension does support these types directly so, to keep things simple, it is convenient to use Numpy. A two dimensional can be declared as follows:
The numpy.ndarray returned by this call displays itself as
np.array() iterates the Python list of lists to get this result.
Another extension, Pandas, built on Numpy, moves closer to a database table by supplying an index of column names and an index of rows:
To allow a list of objects to be converted to a Numpy array or Pandas DataFrame, objects need an __iter__() method that returns each desired attribute of the object replacing the sublists in the abpve example. Optionally a __str__() method to supply a string representation when an instance is seen in a column and a class method columns() that returns a list of column names can also be provided:
Now we need some kind of storage class to hold the table. Thinking that we might want to select items from the structure by name a dictionary suits:
class Struct:
def __init__(self):
self.facet = {}
def add_to_facet(self, item):
self.facet[item.name] = item
@property
def items(self):
return pd.DataFrame(list(self.facet.values()), columns=Person.columns())
Putting it together:
Items are objects:
df = people.items
obj = df.Items[0]
print(obj.hello())
So, that is a basic structure with one facet. In a real application with multiple facets represented by multiple dictionaries it may be useful to be able to select the object attributes returned to build a table on the fly:
Without the complications from joining tables, intermediate tables to represent variable content fields or combining documents, the power of OOP allows attributes to be selected from the immediate object or from other objects referenced from it down to any level.