[Tutor] What are the benefits of template or abstract base classes?

Peter Otten __peter__ at web.de
Mon Jun 8 16:59:50 EDT 2020


boB Stepp wrote:

> On Mon, Jun 8, 2020 at 7:52 AM Peter Otten <__peter__ at web.de> wrote:
>>
>> boB Stepp wrote:
>>
>> > Now in "4.2 Inheritance" at
>> > https://dabeaz-course.github.io/practical->> > python/Notes/04_Classes_objects/02_Inheritance.html
>> >
>> > class TableFormatter:
>> >      def headings(self, headers):
>> >          '''
>> >          Emit the table headings.
>> >          '''
>> >          raise NotImplementedError()
>> >
>> >      def row(self, rowdata):
>> >          '''
>> >          Emit a single row of table data.
>> >          '''
>> >          raise NotImplementedError()
>> >
>> > with the comment:
>> >
>> > "This class does nothing
>>
>> > What are your thoughts?
>>
>> Dunno. Maybe writing code that does nothing is an art form, like poems or
>> songs... and mypy is your arbiter elegantiarum.
> 
> Totally unexpected, quirky response!  Who shall reign supreme in
> directing my cyber-court: Black, MyPy or Pylint?  Pylint critiques
> seemingly every choice, but will back down if challenged.  MyPy only
> judges a subset of cyberlife.  And Black judges with an iron hand.
> Perhaps off with him to the Coliseum fights to perish unless further
> deemed worthy?
> ~(:>))
> 

I don't know Black; with pylint you can cheat a little and get a score of 10 
for your perfect code, or you can cheat some more and get a score of 10 for 
your heap of crap.

mypy on the other hand is open-ended.

Start with TableFormatter, do you want to feed it Any? Of course not, so

print_table(table: Table, formatter: TableFormatter)

We've already established that the table consists of header and rows

class Header:
    column_headers: Sequence[ColumnHeader]

class Rows:
    rows: Iterator[Row]

class Row:
    fields: Sequence[Field]

class Field:
    def format(format: FieldFormat) -> str

class StrField, FloatField, DatetimeField, YouNameItField,...

Table:
    rows: Rows
    header: Header

That looks safe except that we stated that fields are formatted as str. 
What if in addition to csv and text we want to write a binary format?

class Field:
    def format(format: FieldFormat) -> SerializedField

We are starting to get robust. We just need to come up with a FieldFormat 
that works for all subclasses. That can't be hard, so let's look elsewhere.

David used short strings to specify the Formatter -- not very robust, and
Python has enums since ... when? So

class TableFormatterType(enum.Enum):
    text = "txt"
    csv = "csv"

Not as good as the http guys with their Referer, but still nice.

Having another glimpse at our zoo of fields, how can we instantiate the 
right subclass? We certainly need a 

RowFieldFactory

and a

ColumnHeaderFactory.

While we're at it, a

TableFormatterFactory

to cope with our CSVTableFormatter, and TextTableFormatter is de rigueur.
Are we done? Oh dear, do you think our table springs into existence out of 
nowhere?

I'll leave the details of the TableBuilder, or, let's be precise, 
FormatableTableBuilder (or is it PrintableFormatableTableBuilder?) as an 
exercise for the reader...

That said, I feel a bit uneasy about the FieldFormat, we should do it right 
and use a FieldFormatter instead. That gives us flexibility; one formatter 
per field type, composable for width, alignment, color, font,
all governed by a nice little FieldFormatterFactory...




More information about the Tutor mailing list