I'm trying to make a dictionary which calls the name of a restaurant, and the type of cuisine it is known for.
I wanted to create a dictionary so I could call each restaurant type up later. The problem is every method I've tried so far overwrites my value pairs which pertain to each key.
I understand that I somehow need to alter each key so as not to overwrite my values, but so far every attempt I've tried has not been successful. To circumvent that, I tried to place a dictionary within a dictionary. The input/output of the code is also seen below.
Some of the things I attempted are below:
restaurant_dict[restaurant] = value
main:
from nine_two import Restaurant
def increment(min_num, max_num, name_of_variable):
#enter the name of the variable and how many times to increment it
list_1 = []
for x in range(min_num,max_num):
list_1.append(f"{name_of_variable}_{x}")
for variable in list_1:
#return a list of the incremented variables
return list_1
#Created dictionaries & variables
restaurant_dict = {}
restaurant_dict_2 = {}
list_1 = increment(1,4,"Restaurant")
for variable in list_1:
print(f"\n{variable}:")
user_restaurant = input("Enter name of restaurant: ")
user_cuisine = input("Enter cuisine of restaurant: ")
#FIXME attempt to store variables in a callable dictionary
restaurant_dict_2[variable] = restaurant_dict
restaurant_dict["Restaurant"] = user_restaurant
restaurant_dict["Cuisine type"] = user_cuisine
print(restaurant_dict_2)
#ignore this
variable = Restaurant(user_restaurant,user_cuisine)
variable.describe_restaurant()
variable.open_restaurant()
Imported code is:
class Restaurant:
"""Creates a restaurant"""
def __init__(self, restaurant_name, cuisine_type):
"""Intialize name and cuisine attributes."""
self.name = restaurant_name
self.cuisine = cuisine_type
def describe_restaurant(self):
"""describes the restaurant"""
print(f"The {self.name} is a restaurant that specializes in {self.cuisine}.")
def open_restaurant(self):
"""Opens the restaurant"""
print(f"The {self.name} is now open!")
Output of code above
This answer comes in two parts:
How to fix your dictionary problem.
You don't need to use a dictionary at all.
Part 1: How to fix the problem with your dictionaries:
Your problem is that you assign the same restaurant_dict to multiple keys. When you do dict2['key1'] = dict1, you didn't create a copy of dict1 to assign to dict2['key1']. So when later you do dict2['key2'] = dict1, the same dict gets assigned to both key1 and key2. Then, when you change dict1['name'], since the same dict1 is referenced by both key1 and key2, it changes the value in both places.
To fix this, move the line restaurant_dict = {} inside your for variable in list_1: loop, so that you create a new dictionary for each restaurant.
#FIXME attempt to store variables in a callable dictionary
restaurant_dict = {}
restaurant_dict_2[variable] = restaurant_dict
restaurant_dict["Restaurant"] = user_restaurant
restaurant_dict["Cuisine type"] = user_cuisine
Or, better yet, you can simply assign the Restaurant and Cuisine type keys while you're creating the dict
#FIXME attempt to store variables in a callable dictionary
restaurant_dict = {"Restaurant": user_restaurant, "Cuisine type": user_cuisine}
restaurant_dict_2[variable] = restaurant_dict
Part 2: You don't need to use a dictionary at all
Usually when you use a dictionary, you want to map a key to a value. For example, if you were creating a directory of restaurants for every cuisine, you could have a dictionary where the keys were the cuisine type, and the values were a list of restaurants serving that cuisine.
However, in this case, it seems like you are simply making a list of restaurants (because your keys are sequential), so a simple list would suffice. Also, since you have a class to represent a restaurant, you just need to create an object of this class and append it to your list. No need to create dictionaries and Restaurant objects.
restaurants = []
for _ in range(num_restaurants):
user_restaurant = input("Enter name of restaurant: ")
user_cuisine = input("Enter cuisine of restaurant: ")
restaurant = Restaurant(user_restaurant, user_cuisine)
restaurants.append(restaurant)
restaurant.describe_restaurant()
restaurant.open_restaurant()
If you wanted to do the thing I mentioned in the previous paragraph and create a map of cuisines with restaurants, you could then process this list into a dict:
cuisine_restaurants = {}
for rest in restaurants:
cuisine = rest.cuisine
if cuisine not in cuisine_restaurants:
cuisine_restaurants[cuisine] = []
cuisine_restaurants[cuisine].append(rest)
Then, you could ask the user for a cuisine, and show all restaurants that serve that cuisine without having to re-iterate over the entire restaurants list:
c = input("What would you like to eat today?")
suggested_rest = cuisine_restaurants.get(c, []) # .get() returns the second argument if the key given by c doesn't exist
print("You could eat at: ")
for r in suggested_rest:
r.describe_restaurant()
Related
I have a class called Student, where they have two attributes: studentName and a unique number for each student, studentID.
In another class, called Course, I already have a function
add_student(self, student) that adds the given student to the given course. I want to create another function add_student_list(self, lst) which intakes a list of studentIDs. I have a for loop which looks at the IDs in lst to see which students to add, I just need to call the add_student(self, student) function for the ones in lst, however, I'm unable to do this, as I only have an id, and not the student object.
So my question is, how can I call the necessary student object based on the unique ID?
EDIT: here's the relevant part for my code:
import itertools
import pandas as pd
class Student (object):
#The following two objects are used to assign them unique IDs and to keep track of them.
id_iter = itertools.count()
all_students = pd.DataFrame(columns=["Student", "Student ID"])
#Adding a new student:
def __init__(self, studentName):
#The name of the student will be given, the ID will be generated:
self.studentName = [studentName, next(self.id_iter)]
#The new student will have a list of courses attended:
self.courses = pd.DataFrame(columns=["Course", "Course ID", "Passed/Failed", "Completed Assignments"])
#The new student will be added to the list of all students:
Student.all_students = pd.concat([Student.all_students, pd.DataFrame.from_dict({"Student": self.studentName[0], "Student ID": self.studentName[1]}, orient = "index")], ignore_index = True, axis = 1)
Student.all_students = Student.all_students.dropna(axis=1)
def __str__(self):
return str(self.studentName)
class Course (object):
#The two objects are similar to that of the student class:
id_iter = itertools.count()
all_courses = pd.DataFrame(columns=["Course", "Course ID"])
#the courses are similarly added as students above
def add_student(self,student,completed_assignments):
#this adds students with the number of assingments they completed (not relevant), the code is not relevant
def add_student_list(self, lst):
for i in range(0,len(lst)):
for j in range(0,len(Student.all_students.swapaxes("index", "columns"))):
if lst[i][0] == Student.all_students[j][1]:
self.add_student()
Two methods:
Store your students in a dictionary with a id as the key. Than can retrieve the students based on their ids.
Search through the students everytime you have a list.
ids_to_search = [2, 34, 3]
students = [student for student in students if student.id==id_to_search]
I'm writing a script to find the moving average of different stocks. This script runs continuously, looping through my API call to add the current price to a list before averaging it. This works fine, however I'd like to be able to put this into a function to where the only input I need to give it is the name of the stock. I'd like this script to work for as many stocks as I want to specify, at the same time. That's where I run into issues because for each stock I have I need to have an empty list predefined that can hold the pricing information.
I've been trying to use the name of the stock to then create a related list, but as I now understand it it's not a great idea using one variable name to create another variable, so I'm not sure what to do. I believe the usual solution here would be to use a dictionary, but I'm a beginner to programming in general so I haven't figured out how to fit that into my situation. Any help would be greatly appreciated.
def sma(stock_name):
list_exists = stock_name + "_list" in locals() or stock_name + "_list" in globals()
if list_exists:
print()
else:
stock_name + "_list" = [] # Problem line, I would like for this to create a list called stock_name_list
stock_price = requests.get("myapi.com", params={"stock_name": stock_name, "bla bla": "blah"})
stock_name_list.append(stock_price)
When you have an operation based on a version of the data specific to that operation, that is usually a good time to think about using classes. This particular proposed class will encapsulate the name of a stock, the list of data specific to it, and perform sma on it:
class Stock:
n = 10
def __init__(self, name):
self.name = name
self.data = []
def sma(self):
stock_price = requests.get("myapi.com", params={"stock_name": self.stock_name, "bla bla": "blah"})
self.data.append(stock_price)
window = self.data[-n:]
return sum(window) / len(window)
Now you can maintain a dictionary of these objects. Any time you encounter a new stock, you just add an item to the dictionary:
stocks = {}
def sma(name):
stock = stocks.get(name)
if name is None: # None is what get returns when the key is missing
stock = Stock(name)
stocks[name] = stock
return stock.sma()
The nice thing is that you now have a dictionary of named datasets. If you want to add a different statistic, just add a method to the Stock class that implements it.
I defined a global sma function here that calls the eponymous method on the object it finds in your dictionary. You can carry encapsulation to an exterme by making the method perform the action of the function if called statically with a name instead of an instance. For example:
class Stock:
n = 10
named_stocks = {} # This is a class variable that replaces the global stocks
def __init__(self, name):
self.name = name
self.data = []
def sma(self):
if isinstance(self, str):
self = Stock.get_stock(self)
stock_price = requests.get("myapi.com", params={"stock_name": self.stock_name, "bla bla": "blah"})
self.data.append(stock_price)
window = self.data[-n:]
return sum(window) / len(window)
#classmethod
def get_stock(cls, name):
stock = cls.named_stocks.get(name)
if stock is None:
stock = cls(name)
cls.named_stocks[name] = stock
return stock
Now that there is a check for isinstance(self, str), you can call the sma method in one of two ways. You can all it directly on an instance, which knows its own name:
aapl = Stock('AAPL')
aapl.sma()
OR
Stock.get_stock('AAPL').sma()
Alternatively, you can call it on the class, and pass in a name:
Stock.sma('AAPL')
use defaultdict
from collections import defaultdict
stock_name_to_stock_prices = defaultdict(list)
stock_name_to_stock_prices['STOCK_NAME'].append(123.45)
So I want to create a function that accepts values for dictionary, creates new dictionary and returns it. Then I want to assign that value in other places of code. But I get Type Error dict object is not callable. How can I do this?
def shoe(brand, model):
shoe = {}
shoe['brand'] = brand
shoe['model'] = model
return shoe
shoes_list = []
shoe = {}
shoe = shoe('Some Brand', 'Some model')
print(shoe)
def shoe(brand, model):
Here you create a function named shoe.
shoe = {}
Now you create a variable named shoe and assign a dictionary to it. This isn't a problem yet since this variable is local inside of the function. However, it can be very confusing to reuse the same name in this way. I suggest changing this variable's name.
shoe['brand'] = brand
shoe['model'] = model
return shoe
shoes_list = []
shoe = {}
Now you are reassigning the name shoe to refer to an empty dictionary instead of the function that it used to refer to. This will cause later calls to the function with shoe() to fail.
shoe = shoe('Some Brand', 'Some model')
And then you try to assign the return value of the function to the name shoe(). I assume this is where the function call fails. Note that if you fix this, you don't need shoe = {} at all.
print(shoe)
You are using the same name for two different things: once for the name of your function and once for the name of your dictionary. Use two different names to fix the problem. In general, function names should be verbs. So you can do get_shoe() or create_shoe() for the function name. Then using the noun shoe for the dictionary will be fine.
You need your function and your original dict to have different names:
def make_shoe(brand, model):
shoe = {}
shoe['brand'] = brand
shoe['model'] = model
return shoe
shoes_list = []
shoe = {}
shoe = make_shoe('Some Brand', 'Some model')
print(shoe)
Note also that you are not filling in the dict you stored in shoe; you are making a new dict to replace it. If you want to fill it in, you would do something like this:
def fill_in(brand, model, dest):
dest['brand'] = brand
dest['model'] = model
shoes_list = []
shoe = {}
fill_in('Some Brand', 'Some model', shoe)
print(shoe)
I am trying to add a new value to an existing class instance, but I fail. I will directly explain what I am trying to do and will show my code:
Let's say I have a number of people with different names and they have subjects with different value. The input should look like this:
Joe -> car -> 5000
Mike -> house -> 100000
John -> phone -> 1000
Joe -> house -> 80000
etc.
When I get an input with the same name, I should append the new subject to the existing one and make a list from all the subjects and adding the two values.
At the end, when I get an input:
Joe vs John
I should compare them only if they have at least one subject from the same category (in this example it will be "house") and this continues till I get the command "Stop".
class Person:
def __init__(self, name, subject, price):
self.name = name
self.subject = subject
self.price = price
people_list = []
while True:
data_input = input().split(" -> ")
if data_input[0] == "Stop":
break
elif len(data_input) == 3:
name, subject, price = data_input[0], data_input[1], data_input[2]
same_name = [x for x in people_list if x.name == name]
if len(same_name)>0:
(......)
else:
person = Person(name, subject, price)
people_list.append(person)
else:
info = data_input[0].split()
name_1, name_2 = info[0], info[2]
....
Therefore I have 3 questions:
Can I add the new subject and its value somehow in the class directly? This would create one list with all the subjects and one list with all the prices for each name in the class, right?
If this is not possible, can I somehow append the new subjects in the list (people_list in this example)? I think this is not possible or if possible, then much more complicated.
How can I search in the class without using list comprehension?
Thank you very much in advance!
I just started programming and I decided to use Python for my first attempts at coding, and I am now practicing with classes and objects.
I apologize if the question I am about to ask has been asked before, but I can't seem to find answers anywhere, so here it goes.
I have a file that contains a class. Below the full code I have written :
#class file
#class prodotti refers to "register" with products in stock and their prices
class Prodotti(): #class Prodotti() contains products from register and their relative specs
def __init__(self, nome="", #name of product
prezzo=0, #product price
quantità=0,): #stock quantity of product
self.nome=nome
self.prezzo=prezzo
self.quantità=quantità
def newproduct(self): #method appends new product and its specs to the end of this file
name=input("Inserire nuovo prodotto: ")
f=open("cassa3.py", "a")
f.write(name + "=Prodotti(nome='" + name + "', ")
price=input("Inserire prezzo prodotto: ")
f.write("prezzo=" + price + ", quantità=0)\n")
f.close()
def tellprice(self): #method should return price of object
inp=input("Di quale prodotto vuoi conoscere il prezzo? ") #asks user which product they want to know the price of
if inp=Prodotti():
print(inp.prezzo)
#class objects
#user can insert new products that are saved below
tortino=Prodotti(nome="Tortino al cioccolato", prezzo=3.4, quantità=0)
muffincioccolato =Prodotti(nome="Muffin al cioccolato", prezzo=1.8, quantità=0)
cupcake=Prodotti(nome='cupcake', prezzo=2, quantità=0)
In another file, saved in the same directory, I have the main program:
from cassa3 import Prodotti #file cassa3.py in same directory as this file
if __name__=="__main__":
P=Prodotti()
P.tellprice()
As you may tell from the code above, what I want method tellprice() to do is to ask the user what product they want to know the price of.
However, I just don't know how to make the user input correspond to a class object, so that I can access its attributes.
Can someone explain how i could manage to do that?
Thanks in advance.
Before you will be able to solve this issue, you will need to fix the design problem you have.
Your comment says # class Prodotti() contains products from register and their relative specs but it is not quite true. This class contains a single product with its name, price and quantity.
You will need to define another class (perhaps Register) that will actually store a list (or dictionary if product names are unique for efficient lookup, or whatever) of products (instances of Prodotti).
The tellprice method currently makes no sense. It simply creates a new instance of Prodotti and the if condition will never be True.
Also, it is highly suggested to use English names in code.
Consider the below example as a general guide:
class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
# (... some other methods ... )
class Register:
def __init__(self, products):
# this will store the products in a dictionary with products names as keys
# and Product instances as values for an efficient look up by tell_price
self.products = {product.name: product for product in products}
def tell_price(self):
name = input('Which product would you like to know the price of?')
# this will raise KeyError if user inputs a non-existing product name
# and should be caught, or use .get(...) instead
return self.products[name].price
apple = Product('apple', 1, 10)
banana = Product('banana', 2, 2)
register = Register([apple, banana])
print(register.tell_price())
# Which product would you like to know the price of?
>> apple
# 1
I wouldn't make your tellprice include user input.
def tellprice(self): #method should return price of object
return self.price
Then in main (this is significantly simplified):
inp = input("Di quale prodotto vuoi conoscere il prezzo? ")
print(inp.tellprice)
Obviously this assumes they put in the correct product name, so some way of indicating to the user that they're incorrect might be useful