I'm trying to understand an observer class, but I don't understand how to implement it in practice.
I have a class that has 4 functions in relation to a .txt database- add student, delete student, sort and show student database, and search a student. I want it to send out an automatic message to all students when another student is added or deleted.
This is what I have so far, based off a guide I've been looking at:
class ObservableEvent:
def __init__(self):
self.students = []
def register_student(self, student):
self.students.append(student)
def notify_allStudents(self, *args, **kwargs):
for student in self.students:
student.notify(self, *args, **kwargs)
class Observer:
def __init__(self, observable):
observable.register_student(self)
def notify(self, message, observable):
print("Got", message, "From", observable)
subject = ObservableEvent()
student = Observer(subject)
I think its just the last part I'm having the biggest issue with (I hope), concerning the notify_allStudents part. Whenever I try to pass more than 1 positional argument, it doesn't work. So far I have this:
class Student():
def __init__(self, data):
self.data = data
pass
def AddStudent(self, data):
firstName = input('First Name: ')
lastName = input("\nLast Name: ")
email = input('\nEmail Address: ')
campus = input('\nCampus: ')
year = '22'
generated_id = firstName[0:3] + lastName[0:3] + year
newStudent = [generated_id, firstName, lastName, email, campus]
f = open(data, "a")
f.write('\n')
for info in newStudent:
f.write(info)
f.write('\t')
f.close()
pass
Then here is where I have the above ObserverEvent and Observer classes.
And here is the rest:
ans=True
while ans:
print ("""
---------------------------------------------------
Welcome to the QUICK SORT / LINEAR SEARCH Program
1.ADD NEW STUDENT
2.DELETE STUDENT
3.SHOW STUDENTS
4.SEARCH STUDENT
5.ADD COURSE TO STUDENT
Type EXIT to quit the application
""")
ans=input("What would you like to do? ")
if ans=="1":
print("""
*******************
STUDENT ADD MENU
*******************
""")
Student.AddStudent(input, "studentMockData_AS2.txt")
print("\nStudent Added")
subject.notify_allStudents("A student has been added to the database.")
I'm currently getting this in the console: Got <__main__.ObservableEvent object at 0x00000154909BB460> From A student has been added to the database.
I'm honestly really lost on this. The example I was given was subject.notify_observers("test", kw="python"), but the *args and **kwargs are really throwing me. It throws an error of too many positional arguments if I include more than 1, but I thought the whole point of kwargs was to input more than 1. I'm also not sure why I would need to use a dict in this scenario. I don't even understand what I'm not understanding about this, but clearly I'm not doing it right. Any assistance would be hugely appreciated.
EDIT: I'm aware that my class Student is badly done, but I have to leave it as is.
Related
I have to create a list of students. Each student has personal info(name date of birth, etc.), grades(math, English, science) and I need to only print out students who have a grade in math higher than the one in English but lower than the one they have in science. I created the classes but I'm having a little bit of trouble because the personal info, date of birth and grades have to be all different classes.
This is that I have for the classes, they are in order: personal_info, date_of_birth and grades
class Student:
def __init__(self):
self.date = date_of_birth
self.grades = grades()
# And so on
s = Student()
s.date.function_in_birth_class()
First of all make sure you definitely need all 3 classes. By data-object relationship all information related to the Student class can be a self.property. This way when you create an instance of a Student you just pass to the construtor all the data and use conditional statements to print out the Students that meet your criteria.
Alternatively if for some reason you want to keep all 3 separate (don't recommend it) as you have done so far you can instantiate the 3 classes and inject them to the constructor of the Student class like:
names = Names(name='John', surname='Dowe')
date_of_birth = DateOfBirth(day=1, month=1, year=1970)
grades = Grades(math=1, english=2, science=3)
class Student(names, date_of_birth, grades)
def __init__(self):
self.names = names
self.date_of_birth = date_of_birth,
self.grades = grades
def am_i_eligible():
if (self.grades.english < self.grades.math < self.grades.science):
print("First research and read documentation, then check university of youtube, then ask someone to make your homework.")
new_student = Student(names, date_of_birth, grades)
print(new_student.grades.math)
print(new_student.names.name)
print("Never post question as screenshot and do the effort to translate it to english so variable names are meaningful to us.")
new_student.am_i_eligible()
Suppose I had this class
class employee(object)
def __init__(self,name):
return self.name
def something(self):
pass
...
Leading to
if __name__== "__main__":
name = input("what is your name ")
user1 = employee(name)
user1.something()
...
I want the user1 instance to be the name inputted by the user so that I can have unique instances. How do I go about adding instances based on user input in the main section?
so if I run the program and inputted "tim", the outcome I would want is:
tim.name = "tim"
....
UPDATE
Seems like the above is unclear, let me try to explain using my actual code:
So I have this Spotify API:
class Spotify(object):
def __init__(self,user):
self.client_id = ''
self.client_secret = ''
def client_credentials(self):
pass
def get_header_token(self):
pass
...
In the end,
if __name__== "__main__":
user = input("Enter username ")
user = Spotify(user)
user.request_author()
...
I am trying to get the user variable to the input the user provides, such as if the user inputted "tim123", the user variable would also be tim123.
So I could perform:
tim123.name
Think my mind is going completely blank and there should be an easy solution for this. I am sure this is very unpractical but I don't know how I would do this in case I ever needed to.
Change
return self.name
to
self.name = name
if name== "main":
variable_name = raw_input("Enter variable name:") # User.
enters "tim123"
name = input("Enter Name")
globals()[variable_name] = employee(name)
tim123.name
Based on your comment, it sounds like you are looking for exec() or eval(). Link. My solution would be to do something like:
class employee(object):
def __init__(self,name):
self.name = name
name = input("what is your name ")
exec(f"{name} = employee('{name}')")
(and then you would access joe.name, if the user inputted joe, or bob.name, if the user inputted bob, etc.).
Alternatively, you could use locals() or globals()
Hope this helped!
I am creating a class structure in python for a city, that stores the name, country, population and language for a city, all of which are input by the user. The information shall then be printed.
I think that I may be successful in storing the information within the class structure (although this may be wrong as well), but I am unsuccessful in printing the information. Currently, I am receiving the error that int object is not subscriptable.
class User():
def _init_(self, username, password, email, numOfLogins):
User.username = username
User.password = password
User.email = email
User.numOfLogins = numOfLogins
#User Record Array Creation
def createUserArray(num , User):
UserArray = []
for x in range(num):
UserArray.append(User)
return UserArray
#User Record Array Population
def populateUserArray(num, UserArray):
for x in range(len(userArray)):
UserArray[x].username = str(input("Enter username."))
UserArray[x].password = str(input("Enter password."))
UserArray[x].email = str(input("Enter email address."))
UserArray[x].numOfLogins = int(input("Enter number of logins."))
return UserArray
#User Record Array Display
def displayUserArray(UserArray, num):
for x in range(len(userArray)):
print(UserArray[x].username, UserArray[x].password, UserArray[x].email, str(UserArray[x].numOfLogins))
#Top Level Program
numOfUsers = 3
userArray = createUserArray(numOfUsers, User)
userArray = populateUserArray(numOfUsers, userArray)
displayUserArray(numOfUsers, userArray)
The contents of the class should all be displayed at the end of the program, but at the minute my program crashes due to the error - int object is not subscriptable.
you can always implement the method : __str__(self) of an object , and then when you just print it with :
your_obj = User(...)
print your_obj
your __str__(self) will be called and you can return from it whatever you want to print.
for example:
def __self__(self):
return `this class has the following attributes: %s %s %s %s` % (self.username,self.password,self.email ,self.numOfLogins )
and this what will get print, i think it is more efficient and well coded to work like that and not creating a function that print each class attribute separately.
The cause of your error is quite simple and obvious: you defined the function as displayUserArray(UserArray, num) but call it with displayUserArray(numOfUsers, userArray) - IOW you pass the arguments in the wrong order.
This being said, almost all your code is wrong, you obviously don't get the difference between a class and instance and how to use a class to create instances. I strongly suggest you read at least the official tutorial, and check a couple other tutorial and/or example code on the topic of classes and instances.
I'm new to OOP and this is my first shot at creating a Python class. I am trying to make my 3 variables private and so that only the methods update the info (enforce encapsulation). It seems that if I remove the setters and getters methods from my class, it has no impact on my code (must be the initializer method doing the work?). What can I do to improve this? Thanks.
Edit- i've updated my code and removed the init. My getters are not working now.
#Instantiate a new Pet Instance.
myPet = Pet()
#Get input from user.
myPet.setName = input("Enter the pet's name: ")
myPet.setTypes = input("Enter the pet's type (Dog, Cat, Bird, etc.): ")
myPet.setAge = input("Enter the pet's age (in years): ")
while myPet.setAge.isalpha():
print()
print("Age cannot contain numbers. Try again.")
myPet.setAge = input("Enter the pet's age (in years): ")
#Call the showPetInfo module using new instanced object.
myPet.showPetInfo()
class Pet:
#Fields of the Pet Class.
__PetName = ""
__PetType = ""
__PetAge = ""
#Setter methods.
def setName(self,name):
self.__PetName = name
def setTypes(self,types):
self.__PetType = types
def setAge(self,age):
self.__PetAge = age
#Getter methods.
#property
def getName(self):
return self.__PetName
#property
def getType(self):
return self.__PetType
#property
def getAge(self):
return self.__PetAge
def showPetInfo(self):
print("\n \n \n \n")
print("Here is your pet's information. Your pet's name is {}, it is a {} and it is {} years old.".format(self.getName,self.getType,self.getAge))
main()
you are unfortunately right, they use to say setters/getters are contracts doing restriction for adults... (if I tell you "dont touch it" then you shoulntd touch it) but there is nothing restricting you and you can modify them!
same "feature" can be observed with "constants"... do in the jupyther or the terminal this
import math
math.pi = 1
a = math.pi
a
math.pi
and you will see that you now modified the constant pi value to 1
many sugest to usse properties but that is not a capsulation at all, that is just sugar syntax for the same "adults contract" IMHO :)
so to your question
What can I do to improve this?
document the code you are writing so the other part using it is aware about how the code, instances states in objects must be handled
I'm Code doesn't seem to work, I am trying to get input of a job, category, and salary, and store the input
class Jobs:
def GetJob(self):
name = raw_input('Enter a Job Title: ')
category = raw_input('Enter what Category that Job is: ')
salary = raw_input('Enter the salary of that Job: ')
print name,category, salary
def __init__(self,name,category,salary):
self.name = Jobs.GetJob(name)
self.category = Jobs.GetJob(category)
self.salary = Jobs.GetJob(salary)
GetJob = Jobs()
print GetJob
Your code is totally out of good OOP practices, and the first part eandersson's answer too…
A class has for role to store values, get/set them and return (or apply) transformations to its encapsulated values. What you tried to achieve is totally nonsense: you're calling the GetJob method of the Jobs class inside another method. It could work if you would have written:
def __init__(self,name…):
self.name = Jobs.GetJob(self, name)
…
But that would be a wrong way to design your program. You'd better stick your class to hold your values and making it good at that, and make another function that helps populate your class:
class Jobs:
def __init__(self, name, category, salary):
self.name = name
self.category = category
self.salary = salary
def __repr__(self):
return "Jobs<%s,%s,%s>" % (self.name, self.category, self.salary)
def GetJob():
name = raw_input('Enter a Job Title: ')
category = raw_input('Enter what Category that Job is: ')
salary = raw_input('Enter the salary of that Job: ')
return Jobs(name, category, salary)
print GetJob()
I do not agree with eandersson's approach because it deceives the purpose of the constructor, by directly calling the GetJob method. Then GetJob is not useful. And one would want to be able to use the Job class without always having the raw inputs at construction. EDIT: valid only as a comment on the first part of his answer.
And finally, I think that you really misunderstands a lot about programming. You should better read thoroughly a python course like the ones on http://wiki.python.org/moin/BeginnersGuide/NonProgrammers, because there's really a lot of concepts you ignored to be able to write something like that.
go have a look at:
http://hetland.org/writing/instant-hacking.html
http://www.learnpython.org/
http://cscircles.cemc.uwaterloo.ca/
http://learnpythonthehardway.org/book/