How to validate class parameters in __init__? - python

I've been searching a lot for this type of problem, haven't found a single similar question on SO yet.
I have tried using a for loop to put some validation in the train's init that would disregard those passengers although with no success.
tl;dr - How do I validate which passengers will be in the passengers list when I know that some of the passengers in the passengers list are ineligble to be in the train, due to seat_nr out of range or the carriage_nr out of range.
"""Train."""
class Train:
def __init__(self, passengers: list, carriages: int, seats_in_carriage: int):
#--Insert validation for passengers allowed on train--#
self._passengers = passengers
self._carriages = carriages
self._seats_in_carriage = seats_in_carriage
#property
def passengers(self) -> list:
return self._passengers
#property
def carriages(self) -> int:
return self._carriages
#property
def seats_in_carriage(self) -> int:
return self._seats_in_carriage
def get_seats_in_train(self) -> int:
return self._seats_in_carriage * self._carriages
def get_number_of_passengers(self) -> int:
return len(self._passengers)
def get_passengers_in_carriages(self) -> dict:
return {}
#passengers.setter
def passengers(self, value_list: list):
self._passengers = value_list
#carriages.setter
def carriages(self, value: int):
self._carriages = value
#seats_in_carriage.setter
def seats_in_carriage(self, value: int):
self._seats_in_carriage = value
class Passenger:
def __init__(self, passenger_id: str, seat: str):
self.carriage_number = seat.split("-")[0]
self.seat_number = seat.split("-")[1]
self._seat = seat
self._passenger_id = passenger_id
def __dict__(self):
if str(2) >= self.seat_number > str(0) and self.carriage_number <= str(3):
passenger_dct = {'id': str(self._passenger_id), 'seat': str(self._seat)}
return passenger_dct
if __name__ == '__main__':
passengers = [
Passenger('test', '1-2'), #--"test"= passenger_id, "x-y" : x= carriage_nr, y= seat_nr// valid
Passenger('test2', '2-3'), #-- invalid, seat_nr=3, train carriage has only 2 seats.
Passenger('test3', '4-2'), #-- invalid, carriage_nr = 4, train only has 3 carriages.
Passenger('test4', '3-2'), #-- valid
Passenger('test5', '1-1'), #-- valid
Passenger('test6', '1-0'), #-- invalid, no seat_nr 0 on train carriage
]
assert passengers[0].__dict__() == {'id': 'test', 'seat': '1-2'}
t = Train(passengers, 3, 2) #--passengers list, number of carriages, number of seats in carriage.
print(t.get_number_of_passengers()) # -- Should print 3, instead prints all 6.
Any info regarding to the topic is much appreciated, thanks in advance!

I think the solution is pretty straightforward and I'm not sure why this wouldn't work: "I have tried using a for loop to put some validation in the train's init that would disregard those passengers although with no success." Essentially you can just loop through the passenger list and filter out invalid passenger objects as such:
self._passengers = list(filter(lambda p: p.seat_number is valid, passengers))
This uses a lambda function to check certain criteria for including them in the final list. Also your getters and setters don't currently do anything so they are kind of pointless.

Related

Adding and Deleting Values from Dictionary through Object Oriented Programming - Python

I am trying to create a Python program which has the details of power grids and the houses connected to each of those power grids.
I have mainly two tasks to handle, one to add houses to the connection list of each power grid and remove them.
Following is the class for my house:
class House:
def __init__(self, number, power):
self.house_no = number
self.power_required = power
self.assigned_propagator_no = -1
def assign_propagtor(self, number):
self.assigned_propagator_no = number
def __str__(self):
return f"house_no: {self.house_no} power_required: {self.power_required}"
I have a propagator class which is basically used to store all the details and connect between the houses and the power grids:
class Propagator:
def __init__(self, number, max_power):
self.propagator_no = number
self.maximum_power = max_power
self.power_remaining = max_power
self.houses_connected = list()
def __str__(self):
return f"no : {self.propagator_no} max_power: {self.maximum_power} power_remaining: {self.power_remaining}"
def connected_houses_info(self):
for house,_ in self.houses_connected:
print(house)
# check if the house is connected part of the list or not.
def is_house_present(self, house_no):
if house_no in self.houses_connected:
return self.houses_connected.index(house_no)
else:
return -1
# Add the house in the list.
# Before adding check if the house is already connected
def add_house(self, house:House):
if house.assigned_propagator_no != -1:
print('Already exists!')
else:
self.houses_connected.append(house.house_no)
# Remove the house from the list, before removing need to check
# if the house is in the assigned propoagtor list.
def remove_house(self, house_no:int):
pass
Similarly I have created the class for my power grid:
class PowerGrid:
def __init__(self):
self.propagators = dict()
# Adding the propagtor into in the dictionary.
# Check if the propagator is not part of the dictioary already
# It will not posess any value in the beginning.
def add_propagator(self, propagator:Propagator):
pass
# Removing the propagtor into in the dictionary.
# Check if the propagator is part of the dictioary or not
def remove_propagator(self, propagator_no):
pass
def add_house(self, house:House, propagator_no:int):
if propagator_no in self.propagators:
return self.propagators[propagator_no].add_house(house)
else:
return False
def remove_house(self, house_no:int, propagator_no:int):
if propagator_no in self.propagators:
return self.propagators[propagator_no].remove_house(house_no)
else:
return False
class Propagator:
def __init__(self, number, max_power):
self.propagator_no = number
self.maximum_power = max_power
self.power_remaining = max_power
self.houses_connected = list()
def __str__(self):
return f"no : {self.propagator_no} max_power: {self.maximum_power} power_remaining: {self.power_remaining}"
def connected_houses_info(self):
for house,_ in self.houses_connected:
print(house)
# check if the house is connected part of the list or not.
def is_house_present(self, house_no):
if house_no in self.houses_connected:
return self.houses_connected.index(house_no)
else:
return -1
# Add the house in the list.
# Before adding check if the house is already connected
def add_house(self, house:House):
pass
# Remove the house from the list, before removing need to check
# if the house is in the assigned propoagtor list.
def remove_house(self, house_no:int):
pass
The main function to create the power grid is as follows:
def create_power_grid():
power_grid = PowerGrid()
with open('app.csv', newline='') as csvfile: # app.csv image provided later
reader = csv.DictReader(csvfile)
for row in reader:
entity_type = row['Type']
if entity_type == "propagator":
propagator = Propagator(int(row['Entity_Number']), int(row['Power']))
power_grid.add_propagator(propagator)
elif entity_type == "house":
house = House(int(row['Entity_Number']), int(row['Power']))
house.assigned_propagator_no = int(row['Assigned_Propagator'])
power_grid.add_house(house, int(row['Assigned_Propagator']))
return power_grid
if __name__ == "__main__":
power_grid = create_power_grid()
for _, propagator in power_grid.propagators.items():
#Printing the propagator information
print(f"Propagator No : {propagator.propagator_no}")
print("------------Propagator Information-----------------")
print(propagator)
print("------------Connected Houses Information-----------------")
propagator.connected_houses_info()
print("\n")
print("----Removing House 1014 from Propagator 1002----")
if power_grid.remove_house(1014, 1002):
print("House 1014 is successfully removed from Propagator 1002")
else:
print("House 1014 is not connected with Propagator 1002")
print("\n----Removing House 1024 from Propagator 1003----")
if power_grid.remove_house(1024, 1003):
print("House 1024 is successfully removed from Propagator 1003")
else:
print("House 1024 is not connected with Propagator 1003")
I have made certain changes to the add_propagator function inside class PowerGrid as follows:
def add_propagator(self, propagator:Propagator):
if (propagator.propagator_no not in self.propagators.keys()):
self.propagators[propagator.propagator_no] = {}
self.propagators[propagator.propagator_no]['max_power'] = propagator.maximum_power
self.propagators[propagator.propagator_no]['houses'] = []
But I am getting an error:
AttributeError: 'dict' object has no attribute 'add_house'
for the following part:
def add_house(self, house:House, propagator_no:int):
if propagator_no in self.propagators:
return self.propagators[propagator_no].add_house(house)
else:
return False
I have a CSV file from which the values are fed in. The format of the CSV file looks like the following:
I am unable to understand how to define the addition of a house and removal of a house from this, any kind of help with explanation is appreciated.
To have a key correspond to a list in a dictionary in python, note that d[item] is a list::
d = dict()
for item in items_to_add:
if item not in d:
d[item] = []
d[item].append(the_other_item)
# in your case:
if propagator_no not in self.propagators:
self.propagators[propagator_no] = []
self.propagators[propagator_no].append(house)
Your problem is that self.propogators is a dictionary, and therefore has these functions, not add_house.

TypeError: list_content() missing 1 required positional argument: 'key'

I have a python problem that creates a box and puts items in the box and with the help of the list command I can see what's in my box. One example of the execution may go as:
next command> newbox bedroom-box-05
next command> add bedroom-box-05 pillow 3
next command> list bedroom-box-05
Box "bedroom-box-05" contains 3 items.
3 pillow
There are some issues with class MovingBox() as I cannot change the main functions.
class MovingBox():
"""A class for keeping track of the contents ofa moving box. """
def __init__(self,*args):
self = dict()
def add_item(self,key,value =[]):
setattr(self,key,value)
self.add_item=value
def list_content(self,key,value =[]):
setattr(self, key, value)
self.list_content = value
key1 = Keys() # parens
key1.list_content(value)
DON'T CHANGE ANYTHING AFTER THIS LINE
def convert_str_to_int(word):
"""
Converts the parameter string *word* in to an integer value.
"""
try:
result = int(word)
except ValueError:
return None
return result
def newbox(all_boxes, list_of_additional_info):
if len(list_of_additional_info) != 1:
print("Error: wrong number of initial data: can't create a new box.")
return
box_name = list_of_additional_info[0]
all_boxes[box_name] = MovingBox(box_name)
def add_to_box(all_boxes, list_of_additional_info):
if len(list_of_additional_info) != 3:
print("Error: wrong number of elements: can't add into a box.")
return
box_name, item_name, item_count = list_of_additional_info
item_count = convert_str_to_int(item_count)
if item_count is None:
print("Error: not a number: can't add to a box.")
return
if box_name not in all_boxes:
print("Error: box does not exist: can't add to a box.")
return
all_boxes[box_name].add_item(item_name, item_count)
def list_box_content(all_boxes, list_of_additional_info):
"""Displays the contents of a single box in *all_boxes* """
if len(list_of_additional_info) != 1:
print("Error: wrong number of elements: can't list contents.")
return
box_name = list_of_additional_info[0]
if box_name not in all_boxes:
print("Error: box does not exist: can't list content.")
return
all_boxes[box_name].list_content()
def main():
boxes = {}
while True:
command_line = input("next command> ").strip()
if command_line == "":
break
command_words = command_line.split()
first_word = command_words[0]
list_of_other_words = command_words[1:]
if first_word == "quit":
break
elif first_word == "newbox":
newbox(boxes, list_of_other_words)
elif first_word == "add":
add_to_box(boxes, list_of_other_words)
elif first_word == "list":
list_box_content(boxes, list_of_other_words)
if __name__ == "__main__":
main()
Based on the way this class is being used in the code that you're not supposed to change, I don't think you've understood what the MovingBox is supposed to contain/model. Here are examples of how MovingBox is being used:
MovingBox(box_name)
# creates a box named box_name
all_boxes[box_name].add_item(item_name, item_count)
# increments the count of item_name by item_count
all_boxes[box_name].list_content()
# lists the content of the box
The immediate error you're hitting is that list_content isn't supposed to take a parameter, but the larger problem is that what you've tried to implement doesn't match up at all with what the rest of the code is trying to do -- e.g. your implementation of add_item seems to be trying to add a unique item with an arbitrary value (that defaults to [], which has its own problems), when the calling code is actually providing a count of a type of item.
Since MovingBox is seemingly supposed to just be a counter with a custom interface, I'd implement it as a wrapper around collections.Counter:
from collections import Counter
class MovingBox():
"""A class for keeping track of the contents of a moving box. """
def __init__(self, name: str):
self.name = name
self.contents = Counter()
def add_item(self, name: str, count: int) -> None:
self.contents[name] += count
def list_content(self) -> None:
total = sum(self.contents.values())
print(f'Box "{self.name}" contains {total} items.')
for name, count in self.contents.items():
print(f'{count} {name}')
>>> box = MovingBox("a box")
>>> box.add_item("pillow", 3)
>>> box.list_content()
Box "a box" contains 3 items.
3 pillow

Max stack in python - 2 stacks solution

I am trying to build a max stack in python, I am not sure what I am doing wrong.
Here is the question>
Design a max stack data structure that supports the stack operations
and supports finding the stack's maximum element.
Implement the MaxStack class:
MaxStack() Initializes the stack object.
void push(int x) Pushes element x onto the stack.
int pop() Removes the element on top of the stack and returns it.
int top() Gets the element on the top of the stack without removing it.
int peekMax() Retrieves the maximum element in the stack without removing it.
int popMax() Retrieves the maximum element in the stack and removes it.
If there is more than one maximum element, only remove the top-most one.
class MaxStack:
def __init__(self):
self.stack = []
self.stack_max = []
def push(self, x: int) -> None:
self.stack.append(x)
if not self.stack_max or x > self.stack_max[-1][0]:
self.stack_max.append([x, 1])
elif x == self.stack_max[-1][0]:
self.stack_max[-1][1] += 1
else:
self.stack_max.append(self.stack_max[-1])
def pop(self) -> int:
if not self.stack_max or self.stack:
return
if self.stack_max[-1][0] == self.stack[-1]:
self.stack_max[-1][1] -= 1
if self.stack_max[-1][1] == 0:
del self.stack_max[-1]
return self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def peekMax(self) -> int:
if self.stack_max:
return self.stack_max[-1][0]
def popMax(self) -> int:
if self.stack_max:
return self.stack_max.pop()[0]
Example code:
obj = MaxStack()
obj.push(6)
param_2 = obj.pop()
param_3 = obj.top()
param_4 = obj.peekMax()
param_5 = obj.popMax()
Input :
["MaxStack","push","push","push","top","popMax","top","peekMax","pop","top"] [[],[5],[1],[5],[],[],[],[],[],[]]
Output:
[null,null,null,null,5,5,5,5,None,5]
Expected:
[null,null,null,null,5,5,1,5,1,5]
Reference: Leetcode 716. Max Stack
class MaxStack:
def __init__(self,value):#taking some value to avoid empty obj
self.stack=[value]
self.max_=[value,0]
self.length=1
def push(self,value):
self.stack.append(value)
self.length+=1
if value>self.max_[0]:
self.max_[0],self.max_[1]=value,self.length-1
def pop(self):
if self.length==0:
return
elif self.stack[-1]==self.max_[0]:
self.popMax()
else:
self.stack.pop()
self.length-=1
def top(self):
print(self.stack[-1])
def peekMax(self):
print(self.max_[0])
def popMax(self):
if self.length==0 or self.max_[1]==-1:
return
self.stack.pop(self.max_[1])
self.length-=1
self.max_[0],self.max_[1]=-1,-1
for i in range(self.length):
if self.stack[i]>self.max_[0]:
self.max_[0],self.max_[1] = self.stack[i],i
Sorry for the improper indentations, I tried a lot to fix it. Anyways this should work and I wanted to try it out on leetcode but it needs a login. Let me know if there is any issue.
To me, it seems a little confusing to track the count in the tuple of the value, when you could just continue adding to the max stack and counting them from the list if you need that.
class MaxStack:
def __init__(self):
self.stack = []
self.maxes = []
def push(self, n):
self.stack.append(n)
if not self.maxes or n >= max(self.maxes):
self.maxes.append(n)
def pop(self):
if self.stack:
val = self.stack.pop()
if val in self.maxes:
self.maxes.remove(val)
def top(self):
if self.stack:
return self.stack[-1]
def peek_max(self):
if self.maxes:
return self.maxes[-1]
def pop_max(self):
if self.maxes:
return self.maxes.pop()
Then if you need the count of the number of each, just use count():
def max_count(self):
if self.maxes:
return self.maxes.count(max(self.maxes))

How to decrypted [<__main__.Food object at 0x1097ba828>

I am a python newbie. I want display actual names,values and calories instead of [<__main__.Food object at 0x1097ba828>, <__main__.Food object at 0x1097ba860>, <__main__.Food object at 0x1097ba898>] I know this question is very simple,but it would be a great help if you could let me know the answer!
class Food(object):
def __init__(self,n,v,w):
self.name = n
self.value = v
self.calories = w
def getValue(self):
return self.value
def getCal(self):
return self.calories
def density(self):
return self.getValue()/self.getCal()
def __str__(self):
return '<__main__.Food: '+self.name +' '+ self.value+' ' + self.calories
def buildMenu(self):
menu = []
for i in range(len(values)):
menu.append(Food(self.name[i], self.value[i], self.calories[i]))
return menu
names=['burger','fries','coke']
values=[1,2,3]
calories=[100,200,300]
if __name__ == '__main__':
new = Food(names, values, calories)
print(new.buildMenu())
Thank you!
I made two code changes to get what I think you're looking for. The first is to convert values to strings in your str function. The second is to use that.
def __str__(self):
return '<__main__.Food: '+ str(self.name) +' '+ str(self.value)+' ' + str(self.calories)
and
print (str(new)) #instead of print(new.buildMenu())
Now the output is:
<main.Food: ['burger', 'fries', 'coke'] [1, 2, 3] [100, 200, 300]
This is how I would do it, noting that we've created two classes: a separate Food and Menu class. The Menu class has an add method that appends to its foodItems property, though I don't feel like that's really necessary since we can just do direct property assignment:
m.foodItems = < some list of Food objects >
I've removed the confusing buildMenu method from the Food class, and defined __str__ methods for both classes:
class Food(object):
def __init__(self,n,v,w):
self.name = n
self.value = v
self.calories = w
def getValue(self):
return self.value
def getCal(self):
return self.calories
def density(self):
return self.getValue()/self.getCal()
def __str__(self):
return '\t'.join([self.name, str(self.value), str(self.calories)])
class Menu(object):
def __init__(self):
self.foodItems = []
def add(self, foodItem):
self.foodItems.append(foodItem)
def __str__(self):
"""
prints the food items
"""
s = 'Item\tValue\tCalories\n'
s += '\n'.join(str(f) for f in self.foodItems)
return s
names=['burger','fries','coke']
values=[1,2,3]
calories=[100,200,300]
m = Menu()
items = list(Food(n,v,c) for n,v,c in zip(names,values,calories))
m.foodItems = items
print(m)
And outputs like:
The issue you have is that you're printing a list of Food instances, not a single instance at a time. The list type's __str__ operator calls repr on the items the list contains, not str, so your __str__ method does not get run.
A simple fix is to just rename your __str__ method to __repr__.
I'd note that it's a bit strange that you're building a Food instance with lists of values for name, value and calories, just so that you can call a method on it to make a list of Food instances with the individual values. A more Pythoic approach would be to pass the lists to a classmethod that returns the list of instances, without the intermediate instance needing to exist:
#classmethod
def buildMenu(cls, names, values, calories):
menu = []
for i in range(len(values)): # consider using zip instead of looping over indexes
menu.append(cls(names[i], values[i], calories[i]))
return menu
You'd call it on the class:
if __name__ == '__main__':
print(Food.buildMenu(names, values, calories))

Creating Vectors with Python

I'm creating a vector class that has one parameter being the length of a vector. The length is automatically 0 if none is entered by user. If a vector is given a length, however, each number will be set to 0. For example: v(5) would be [0,0,0,0,0] and v() would be [].
This is the code i have thus far, but it's not quite working. Any advice?
class V:
def __init__(self, length = 0):
self.vector = [0]*length
def __str__(self):
print(self.vector)
def __len__(self):
return len(self.vector)
Then i plug in a = V() b = V(5) and when i print(a) and print(b) i get an TypeError. Any advice?
I'd probably cheat and go for sub-classing list:
class V(list):
def __init__(self, length=0):
super(V, self).__init__([0] * length)
This way you get the length, repr and other goodies for free.
class V:
def __init__(self, length = 0):
self.data = [0]*length
def __str__(self):
return '[{}]'.format(', '.join(str(d) for d in self.data))
def __len__(self):
return len(self.data)

Categories

Resources