3
\$\begingroup\$

I have attempted to do Model View Controller in Python for learning. First, I am not sure if dictionaries are faster than lists for about N = 30 (20 to 40) items. Second, how maintainable is this design since I got abstraction but not very much encapsulation? The abstraction comes from abstracting towards to the domain classes.

The classes and their purposes:

  • Table Model is a data class in the domain model.
  • Total Price Model is an algorithm to compute the total price of Table Models.
  • Table File handles File I/O of and sets the fields of Table Model.
  • Table View handles user I/O which is currently command line.
  • main is a driver program to run the code.
class TableModel:
 """
 Data Model of a table
 """
 def __init__(self, key :int, name: str, price_cents: int) -> None:
 """
 :param key: computer generated number
 :param name: name of this what
 :param price_cents: price in USD, in cents, of this what
 """
 self.key = key
 self.name = name
 self.price_cents = price_cents
 def __str__(self) -> str:
 """
 Input: None \n
 Output: string to allow for debuging (print object out) \n
 """
 string = "key: " + str(self.key) + "\n"
 string = string + "name: " + self.name + "\n"
 string = string + "price_cents: " + str(self.price_cents) + "\n"
 return string
class TotalPriceModel:
 """
 Algorithm for total price
 """
 def total_price_cents(self, table_models:dict) -> int:
 """
 :param table_models: the table models
 Output: total price
 """
 cents = 0
 for key in table_models:
 cents = cents + table_models[key].price_cents
 return cents
class TableFile:
 """
 Models the file of table
 Note: this is a text file (for now anyways)
 """
 def __init__(self, table_models:[TableModel]) -> None:
 """
 :param table_models: dict, keys are str(table_model.key) and val are the talbe_model
 """
 self.table_models = table_models
 def to_file(self) -> None:
 """
 Input: None \n
 Output: None \n
 Note: puts info into file \n
 """
 file = open("save_file.txt", "r+")
 name = ""
 price_cents = ""
 key = ""
 for key in range(self.table_models):
 name = self.table_models[key].name
 price_cents = str(self.table_models[key].price_cents)
 key = str(self.table_models[key].key)
 file.write(name + "#" + price_cents + "#" + key)
 file.close()
 def from_file(self) -> None:
 """
 Input: None \n
 Output: None \n
 Note: puts file info into this \n
 """
 file = open("save_file.txt", "r+")
 name = ""
 price_cents = 0
 key = 0
 table_model = None
 #use gen so that the extra space is less
 for line in file.readlines():
 name = line.split("#")[0]
 price_cents = int(line.split("#")[1])
 key = int(line.split("#")[2])
 table_model = TableModel(key, name, price_cents)
 self.table_models.append(table_model)
 file.close()
 def add(self, what:TableModel) -> None:
 """
 :param what: what to add
 Output: None
 """
 self.table_models[str(what.key)] = what
 def remove(self, key:int) -> None:
 """
 :param key: key of the object to remove
 Output: None \n
 Note: if this not in the class, this results in nothing done
 """
 if key in self.table_models:
 del self.table_models[str(key)]
 def change(self, table:TableModel) -> None:
 """
 :param table: table that was changed using the computer \n
 Output: None \n
 """
 self.table_models[str(table.key)] = table
class TableView:
 """
 User Input and User Output
 """
 def __init__(self, tables_model:dict) -> None:
 self.tables = tables_model
 def render(self) -> None:
 """
 Input: None \n
 Output: None \n
 Note: outputs to user
 """
 print("Table View")
 name = ""
 price_cents = ""
 for key in self.tables:
 name = self.tables[key].name
 price_cents = str(self.tables[key].price_cents)
 print(name + " " + price_cents)
 def change_event(self, table: TableModel) -> None:
 """
 :param table: table that was changed using the computer
 Output: None
 """
 self.tables[str(table.key)] = table
 def append_event(self, table: TableModel) -> None:
 """
 :param table: table that was added within the computer
 Output: None
 """
 self.tables[str(table.key)] = table
 def remove_event(self, table: TableModel) -> None:
 """
 :param table: table that was removed from the computer
 Output: None
 """
 if str(table.key) in self.tables:
 del self.tables[str(table.key)]
def main() -> None:
 """
 Input: None \n
 Output: None \n
 Note: Runs the code, can test using std output \n
 """
 table_model = TableModel(0, "Bob's Table", 0)
 table_view = TableView({})
 table_view.append_event(table_model)
 table_view.render()
 print(table_model)
 print("hello world")
if __name__ == "__main__":
 main()
toolic
14.6k5 gold badges29 silver badges204 bronze badges
asked Dec 6, 2020 at 22:54
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Overview

You've done an excellent job:

  • You did a good job partitioning code into functions
  • You used meaningful names for classes, functions and variables
  • You added documentation for the functions
  • The main function makes it easy to see how to run some of the code

Here are some adjustments to consider, mainly for coding style.

Lint check

pylint identified a few style issues.

Consider using with to open a file. This has the side benefit of simplifying the code since there is no need to call close.

Simpler

You can simplify the code in the __str__ function using the += assignment operator:

def __str__(self) -> str:
 """
 Input: None
 Output: string to allow for debuging (print object out)
 """
 string = "key: " + str(self.key) + "\n"
 string += "name: " + self.name + "\n"
 string += "price_cents: " + str(self.price_cents) + "\n"
 return string

Documentation

It is good practice to add a summary of the purpose of the code at top of the file.

Some of the docstrings have a literal \n, while others do not:

def from_file(self) -> None:
 """
 Input: None \n
 Output: None \n
 Note: puts file info into this \n
 """

If you don't need the \n for any reason, I recommend removing them.

Add more information for the TableFile class methods because I could not figure out how to use them. For example, it seems strange that the to_file function uses "r+" for the file open mode to open a file for writing.

f-string

In some instances, using f-strings instead of concatenation may be cleaner. For example, change:

 print(name + " " + price_cents)

to:

 print(f'{name} {price_cents}')

Typo

"debuging" should be "debugging".

"talbe" should be "table".

answered Mar 18, 2024 at 18:29
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.