Implementation of MVC Design Pattern in Python3 - python-3.x

I am trying to implement MVC using Python3.8. I have used this https://www.tutorialspoint.com/python_design_patterns/python_design_patterns_model_view_controller.htm Python2's example for practice.
But, I am receiving the following error:
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
My code is as following:
model.py
import json
class Person:
def __init__(self, first = None, last = None):
self.first = first
self.last = last
def name(self):
return ('%s %s' %(self.first, self.last))
#classmethod
def getAll(self):
database = open('data.txt', 'r')
result = []
jsonList = json.loads(database.read())
for item in jsonList:
item = json.loads(item)
person = Person(item['first'], item['last'])
result.append(person)
return result
view.py
from model import Person
def showAllView(list):
print ('In our db we have %i users. Here they are:' % len(list))
for item in list:
print (item.name())
def startView():
print ('MVC - the simplest example')
print ('Do you want to see everyone in my db?[y/n]')
def endView():
print ('Goodbye!')
controller.py
from model import Person
import view
def showAll():
#gets list of all Person objects
people_in_db = Person.getAll()
return view.showAllView(people_in_db)
def start():
view.startView()
answer = input('Enter y or n')
if answer == 'y':
return showAll()
else:
return view.endView()
if __name__ == "__main__":
start()
Data.txt
[{
"first": "abc",
"last": "xyz"
}]
Please, guide me in this and help me find the error. Thanks in advance.

I have solved the problem myself. The main problem was loading JSON elements twice in model.py, like below:
jsonList = json.loads(database.read())
for item in jsonList:
item = json.loads(item)
Now I have solved it by removing item = json.loads(item).

Related

XML parsing with class will not find the values

I will split a large XML to small branches and than parse only this parts.
I search modified timestamp "mod_time" tag which is avaliable in "contacts" tag, but my object function call, doesn't find the value. In some contacts is also some tags missing completly.
I tried iterfind('tag_name'), iter(), findall('tag_name'), but my program shows no result and I can't figure out for hours, where my failure is.
Here is my XML reduced to two elements:
<?xml version="1.0" encoding = "utf-8"?>
<phonebooks>
<phonebook name="Telefonbuch">
<contact>
<category>0</category>
<person>
<realName>Dummy, Name, Street</realName>
</person>
<telephony nid="1">
<number type="work" prio="1" id="0">012345678</number>
</telephony>
<services />
<setup />
<features doorphone="0" />
<mod_time>1587477163</mod_time>
<uniqueid>358</uniqueid>
</contact>
<contact>
<category>0</category>
<person>
<realName>Foto Name</realName>
</person>
<telephony nid="1">
<number type="home" prio="1" id="0">067856743</number>
</telephony>
<services />
<setup />
<features doorphone="0" />
<mod_time>1547749691</mod_time>
<uniqueid>68</uniqueid>
</contact>
</phonebook>
</phonebooks>
and her what I have done so fare:
import timeit
import xml.etree.ElementTree as ET
class Phonebook:
def __init__(self, xml_file, tag_node):
"""Split tree in contact branches """
self.xml_file = xml_file
self.tag_node = tag_node
# For furter parsing
contacts = []
i = 0
events =('start','end','start-ns','end-ns')
for event, elem in ET.iterparse(self.xml_file, events=events):
if event == 'end' and elem.tag == self.tag_node[0]:
#print(elem.tag)
contacts.append(elem)
par = Contact(elem, i)
par.parse_node(elem, i)
i += 1
elem.clear()
print("Amount of contacts:", len(contacts))
class Contact:
def __init__(self, branch, i):
self.tree = branch
#print(i, self.tree)
def parse_node(self, branch, i):
for node in branch.iterfind('.//mod_time'):
print(node.text)
def main():
elem = Phonebook('new _dummy1.xml',['contact'])
if __name__ == '__main__':
""" Input XML file definition """
starttime=timeit.default_timer()
main()
print('Finished')
print("Runtime:", timeit.default_timer()-starttime)
Output:
Amount of contacts: 2 Finished Runtime: 0.0006361000050674193
Expected output:
1587477163
1547749691
Code
import timeit
import xml.etree.ElementTree as ET
class Phonebook:
def __init__(self, xml_file, selector):
self.xml_file = xml_file
self.selector = selector
root = ET.parse(xml_file)
contacts = root.findall(selector)
print("Amount of contacts:", len(contacts))
for mod_time in contacts:
print(mod_time.text)
def main():
Phonebook('./_dummy1.xml','.//contact/mod_time')
if __name__ == '__main__':
starttime=timeit.default_timer()
main()
print('Finished')
print("Runtime:", timeit.default_timer()-starttime)
Output
$ python test.py
Amount of contacts: 2
1587477163
1547749691
Finished
Runtime: 0.0006627999973716214
I solved now my issue with the handshake of the object data. I create now an instance of Contact which inherit the values from the parent class Phonbook, instead of call Contact from Phonbook Object. Very helpful was the python documentation about the super() function, which refers to this great page. I post my solution, because it's maybe interessting for others who run in similar issues.
Thanks to all who tried to help!
My changed code:
import psutil
import timeit
import xml.etree.ElementTree as ET
class Phonebook:
def __init__(self, file_path):
"""Split tree in contact branches """
self.file_path = file_path
def contacts_list(self, file_path):
contacts = []
events =('start','end','start-ns','end-ns')
for event, elem in ET.iterparse(self.file_path, events=events):
if event == 'end' and elem.tag == 'contact':
contact = elem
contacts.append(contact)
elem.clear()
return contacts
#print("Superclass:",contacts)
class Contact(Phonebook):
def __init__(self, file_path):
super().__init__(file_path)
def search_node(self, contact, searched_tag):
contact_template =['category','person', 'telephony', 'services', 'setup', 'features', 'mod_time', 'uniqueid' ]
node_tag_list = []
list_difference = []
search_list = []
for node in contact:
if node.tag not in node_tag_list:
node_tag_list.append(node.tag)
for element in contact_template:
if element not in node_tag_list:
list_difference.append(element)
for node in contact:
if node.tag == searched_tag and node.tag not in list_difference:
search_list.append(node.text)
#print(node.text)
else:
if len(list_difference) != 0 and searched_tag in list_difference:
message = self.missed_tag(list_difference)
#print(message)
if message not in search_list:
search_list.append(message)
return search_list
def missed_tag(self, list_difference):
for m in list_difference:
message = f'{m} - not assigned'
return message
def main():
con = Contact('dummy.xml')
contacts = con.contacts_list(('dummy.xml'))
mod_time_list =[]
for contact in contacts:
mod_time = con.search_node(contact, 'mod_time')
mod_time_list.append(mod_time)
print(len(mod_time_list))
print(mod_time_list)
if __name__ == '__main__':
""" Input XML file definition """
starttime=timeit.default_timer()
main()
print('Finished')
# Getting % usage of virtual_memory ( 3rd field)
print('RAM memory % used:', psutil.virtual_memory()[2])
# Getting usage of virtual_memory in GB ( 4th field)
print('RAM Used (GB):', psutil.virtual_memory()[3]/1000000000)
print("Runtime:", timeit.default_timer()-starttime)

Is it possible to change the output so that "Arlene" and "Klusman" don't have an extra set of parenthesis around them?

I'm writing code for an assignment where I can't change the main. The way I have it written, it prints like in the screenshot below:
Here is my code:
import csv
class Customer:
def __init__(self, cust_id, name, lastName, companyName, address, city, state, cust_zip):
self.cust_id = cust_id
self.first_name = name
self.last_name = lastName
self.company_name = companyName
self.address = address
self.city = city
self.state = state
self.zip = cust_zip
def getFullName(self):
return(self.first_name, self.last_name)
def getFullAddress(self):
return(self.getFullName(), self.company_name, self.address, self.city, self.state, self.zip)
def get_customers():
myList = []
counter = 0
with open("customers.csv", "r") as csv_file:
reader = csv.reader(csv_file, delimiter = ",")
for row in reader:
if counter!=0:
customer1 = Customer(row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7])
myList.append(customer1)
counter+=1
return myList
def find_customer_by_id(customers, cust_id):
for i in range(len(customers)):
if cust_id == customers[i].cust_id:
return customers[i]
return None
def main():
#main is fully implemented with no modification expected
print("Customer Viewer")
print()
customers = get_customers()
while True:
cust_id = input("Enter customer ID: ").strip()
print()
customer = find_customer_by_id(customers, cust_id)
if customer == None:
print("No customer with that ID.")
print()
else:
print(customer.getFullAddress())
print()
again = input("Continue? (y/n): ").lower()
print()
if again != "y":
break
print("Bye!")
if __name__ == "__main__":
main()
Why are there parenthesis and, can you get rid of them?
I tried to different approaches but nothing changed the output in the intended way

Python: creating a dictionary: {int, class object} in a loop

I'd like to create a dictonary: {int, Class} in a loop, however the class object is being overriden.
I am pretty sure that this is a basic problem, but I am stuck
class Simple:
simpleDic = {
'name': {""},
'age': {1}}
def __init__(self, name, age):
self.simpleDic['name'] = name
self.simpleDic['age'] = age
def __str__(self):
return "{} {}\n".format(self.simpleDic['name'], self.simpleDic['age'])
def foo():
myDict = {}
for x in range(3):
myDict[x] = Simple('Name' + str(x), x)
print(('{}: {}\n'.format("Creating", myDict[x])))
for key in myDict:
print(('{}: {}\n'.format("Printing" + str(key), myDict[key])))
#### Main program here ####
foo()
The output is as follows:
You're problem is on the last print
You're printing myDict[x] when you should print myDict[key]
x contains the last value from the first iteration, so you're practically printing the same key all over
Following your question in this comments:
class Simple:
def __init__(self, name, age):
self.simpleDic = {"name": name, "age": age}
def __str__(self):
return "{} {}\n".format(self.simpleDic['name'], self.simpleDic['age'])
def __repr__(self):
return "{} {}\n".format(self.simpleDic['name'], self.simpleDic['age'])
def foo():
myDict = {}
for x in range(3):
myDict[x] = Simple('Name' + str(x), x)
print(('{}: {}\n'.format("Creating", myDict[x])))
print(myDict)

Error : list.remove(x) : x not in list, I don't understand why

I'm working on a little text-based game and having a problem with removing element from a list.
Here is a code to run that throws the error ValueError: list.remove(x): x not in the list but I don't see why.
LVL = 'lvl'
DAMAGE = 'damage'
Items = {
'Sword':{
LVL : 1,
DAMAGE : 5,
},
'Wand':{
LVL : 1,
DAMAGE : 3,
},
}
class player():
def __init__(self):
self.inventory = []
class item():
def __init__(self, name: str, **kwarg):
self.name = name
self.dmg = kwarg.get(DAMAGE)
self.lvl = kwarg.get(LVL)
def __str__(self):
return self.name
if __name__ == "__main__":
user = player()
for i in Items.keys():
it = item(i, **Items[i])
user.inventory.append(it)
# check user's inventory
print('Inventory after append items :')
for i in user.inventory:
print(i)
# let's say i want the user to drop items
items_name = [i for i in Items.keys()]
items_to_drop = [item(i, **Items[i]) for i in items_name]
for i in items_to_drop:
user.inventory.remove(i)
My guess is that even if the items from user.inventory are the same as those in items_to_drop, the program sees it as two different variables. In which case I do not see how to perform what I want, that is removing items from user.inventory given a list filled with items to remove (because I cannot loop over user.inventory directly right ?)
I apologize if this question has been answered before. I have searched for it but with no success.
In the end, as suggested in comment, I had to overwrite __eq__() method of class item so that Python sees if two same items are actually in both user.inventory and items_to_drop. It works !
If needed, I simply did
def __eq__(self, other):
return self.name == other.name
One easy solution:
# let's say i want the user to drop items
items_name = [i for i in Items.keys()]
items_to_drop = [item(i, **Items[i]) for i in items_name]
for i in items_to_drop:
try:
user.inventory.remove(i)
except:
continue
another one and better one:
# let's say i want the user to drop items
items_name = [i for i in Items.keys()]
items_to_drop = [item(i, **Items[i]) for i in items_name]
invetory_copy = inventory.copy()
for i in inventory:
if i in items_to_drop:
inventory_copy.remove(i)
inventory = inventory_copy

In OOP in python, are different instances of an object when initialised with a default value the same?

I am trying to understand object oriented programming. I am doing this by creating a small poker like program. I have come across a problem whose minimal working example is this:
For this code:
import random
class superthing(object):
def __init__(self,name,listthing=[]):
self.name = name
self.listthing = listthing
def randomlyadd(self):
self.listthing.append(random.randint(1,50))
def __str__(self):
return '\nName: '+str(self.name)+'\nList: '+str(self.listthing)
Aboy = superthing('Aboy')
Aboy.randomlyadd()
print(Aboy)
Anotherboy = superthing('Anotherboy')
Anotherboy.randomlyadd()
print(Anotherboy)
I expect this output :
Name: Aboy
List: [44]
(some number between 1 and 50)
Name: Anotherboy
List: [11]
(again a random number between 1 and 50)
But what I get is:
Name: Aboy
List: [44]
(Meets my expectation)
Name: Anotherboy
List: [44,11]
(it appends this number to the list in the previous instance)
Why is this happening? The context is that two players are dealt a card from a deck. I am sorry if a similar question exists, if it does, I will read up on it if you can just point it out. New to stack overflow. Thanks in advance.
For the non minimal example, I am trying this:
import random
class Card(object):
def __init__(self, suit, value):
self.suit = suit
self.value = value
def getsuit(self):
return self.suit
def getval(self):
return self.value
def __str__(self):
if(self.suit == 'Clubs'):
suitstr = u'\u2663'
elif(self.suit == 'Diamonds'):
suitstr = u'\u2666'
elif(self.suit == 'Hearts'):
suitstr = u'\u2665'
elif(self.suit == 'Spades'):
suitstr = u'\u2660'
if((self.value<11)&(self.value>1)):
valuestr = str(self.value)
elif(self.value == 11):
valuestr = 'J'
elif(self.value == 12):
valuestr = 'Q'
elif(self.value == 13):
valuestr = 'K'
elif((self.value == 1)|(self.value == 14)):
valuestr = 'A'
return(valuestr+suitstr)
class Deck(object):
def __init__(self,DeckCards=[]):
self.DeckCards = DeckCards
def builddeck(self):
suits = ['Hearts','Diamonds','Clubs','Spades']
for suit in suits:
for i in range(13):
self.DeckCards.append(Card(suit,i+1))
def shuffle(self):
for i in range(len(self)):
r = random.randint(0,len(self)-1)
self.DeckCards[i],self.DeckCards[r] = self.DeckCards[r],self.DeckCards[i]
def draw(self):
return self.DeckCards.pop()
def __str__(self):
return str([card.__str__() for card in self.DeckCards])
def __len__(self):
return len(self.DeckCards)
class Player(object):
def __init__(self,Name,PlayerHandcards = [],Balance = 1000):
self.Name = Name
self.Hand = PlayerHandcards
self.Balance = Balance
def deal(self,deck):
self.Hand.append(deck.draw())
def __str__(self):
return 'Name :'+str(self.Name)+'\n'+'Hand: '+str([card.__str__() for card in self.Hand])+'\n'+'Balance: '+str(self.Balance)
deck1 = Deck()
deck1.builddeck()
deck1.shuffle()
Alice = Player('Alice')
Alice.deal(deck1)
print(Alice)
Bob = Player('Bob')
Bob.deal(deck1)
print(Bob)
And after dealing to Bob they both have the same hands. If you have some other suggestions regarding the code, you are welcome to share that as well.
This is a duplicate of “Least Astonishment” and the Mutable Default Argument as indicated by #Mad Physicist. Closing this question for the same.

Resources