For a school project I have to write a python program that records student records and display them.
My school said she wanted a class that represents the school register but I don't know understand how I do that.
I created the following:
class SchoolRegister:
def __init__(self):
ListOfPupils = {}
def REgisterPupil(self, lastname, firstname, schoolID):
ListOfPupils[schoolID] = (lastname, firstname)
sr = SchoolRegister()
sr.REgisterPupil("Thomas", "Lucy", 1)
sr.REgisterPupil("Percival", "Jenny", 2)
I would like to be go through list so I get list out:
1, Thomas, Lucy
2, Percival, Jenny
I searched and found a way of making class act as pupil list thingy, so I can do a for bod in sr but I don't understand it :(
This problem presents a platform upon which we can discuss some interesting Object Oriented programming concepts! We would ideally like to map the real world with code by creating models of the data that represent the real world. This is the inherit value that Object Oriented programming affords us.
Let's use your example.
Our focus is to be able to create records of students that exist (perhaps we should model a student and create parameters which define what a student means to us) and register (we would ideally like to be able to add and remove students from it and be able to retrieve the state of our student body) them in a central place that we can access.
So we can go ahead and implement a simple Student class that represents a student as far as we are concerned (hard to really quantify human beings on a few factors, so let's narrow our focus :D):
class Student:
def __init__(self, id, first_name, last_name):
self.id = id
self.first_name = first_name
self.last_name = last_name
We now have the ability to create objects that represent a student and store that information in a structured way. Now moving on to the the school register, let's think about what sort of data we need. How can we have full awareness of all of the students that exist? A likely data structure we could use could be a list! This grants us the option to (1) store all of the student's that exist (2) Maintain the order in which the student were inserted into the list (or perhaps enrolled at the school).
What if we want to be able to quickly access a Student object though? Perhaps we'd like to know more about a student in the register and we have access to their id. Well in that case we could use a dict which affords us easy student lookups using some sort of unique identifer (i.e. an id).
Let's go ahead and implement a simple example of that:
class SchoolRegister:
def __init__(self):
self.students = {}
def register_student(self, student):
self.students[student.id] = student
def get_student_by_id(self, id):
return self.students[id]
Now we can (1) create a Student, (2) add it to our records, (3) lookup that student information with a key (their id) as shown below:
school_register = SchoolRegister()
john_doe = Student(0, 'John', 'Doe')
school_register.register_student(john_doe)
school_register.get_student_by_id(0) # John Doe!
Suggested Readings:
Classes in Python
What is object oriented programming?
Related
I have just started learning software development and I am modelling my system in a UML Class diagram. I am unsure how I would implement this in code.
To keep things simple let’s assume the followimg example:
There is a Room and a Guest Class with association Room(0..)-Guest(0..) and an association class RoomBooking, which contains booking details. How would I model this in Python if my system wants to see all room bookings made by a particular guest?
Most Python applications developed from a UML design are backed by a relational database, usually via an ORM. In which case your design is pretty trivial: your RoomBooking is a table in the database, and the way you look up all RoomBooking objects for a given Guest is just an ORM query. Keeping it vague rather than using a particular ORM syntax, something like this:
bookings = RoomBooking.select(Guest=guest)
With an RDBMS but no ORM, it's not much different. Something like this:
sql = 'SELECT Room, Guest, Charge, Paid FROM RoomBooking WHERE Guest = ?'
cur = db.execute(sql, (guest.id))
bookings = [RoomBooking(*row) for row in cur]
And this points to what you'd do if you're not using a RDBMS: any relation that would be stored as a table with a foreign key is instead stored as some kind of dict in memory.
For example, you might have a dict mapping guests to sets of room bookings:
bookings = guest_booking[guest]
Or, alternatively, if you don't have a huge number of hotels, you might have this mapping implicit, with each hotel having a 1-to-1 mapping of guests to bookings:
bookings = [hotel.bookings[guest] for hotel in hotels]
Since you're starting off with UML, you're probably thinking in strict OO terms, so you'll want to encapsulate this dict in some class, behind some mutator and accessor methods, so you can ensure that you don't accidentally break any invariants.
There are a few obvious places to put it—a BookingManager object makes sense for the guest-to-set-of-bookings mapping, and the Hotel itself is such an obvious place for the per-hotel-guest-to-booking that I used it without thinking above.
But another place to put it, which is closer to the ORM design, is in a class attribute on the RoomBooking type, accessed by classmethods. This also allows you to extend things if you later need to, e.g., look things up by hotel—you'd then put two dicts as class attributes, and ensure that a single method always updates both of them, so you know they're always consistent.
So, let's look at that:
class RoomBooking
guest_mapping = collections.defaultdict(set)
hotel_mapping = collections.defaultdict(set)
def __init__(self, guest, room):
self.guest, self.room = guest, room
#classmethod
def find_by_guest(cls, guest):
return cls.guest_mapping[guest]
#classmethod
def find_by_hotel(cls, hotel):
return cls.hotel_mapping[hotel]
#classmethod
def add_booking(cls, guest, room):
booking = cls(guest, room)
cls.guest_mapping[guest].add(booking)
cls.hotel_mapping[room.hotel].add(booking)
Of course your Hotel instance probably needs to add the booking as well, so it can raise an exception if two different bookings cover the same room on overlapping dates, whether that happens in RoomBooking.add_booking, or in some higher-level function that calls both Hotel.add_booking and RoomBooking.add_booking.
And if this is multi-threaded (which seems like a good possibility, given that you're heading this far down the Java-inspired design path), you'll need a big lock, or a series of fine-grained locks, around the whole transaction.
For persistence, you probably want to store these mappings along with the public objects. But for a small enough data set, or for a server that rarely restarts, it might be simpler to just persist the public objects, and rebuild the mappings at load time by doing a bunch of add_booking calls as part of the load process.
If you want to make it even more ORM-style, you can have a single find method that takes keyword arguments and manually executes a "query plan" in a trivial way:
#classmethod
def find(cls, guest=None, hotel=None):
if guest is None and hotel is None:
return {booking for bookings in cls.guest_mapping.values()
for booking in bookings}
elif hotel is None:
return cls.guest_mapping[guest]
elif guest is None:
return cls.hotel_mapping[hotel]
else:
return {booking for booking in cls.guest_mapping[guest]
if booking.room.hotel == hotel}
But this is already pushing things to the point where you might want to go back and ask whether you were right to not use an ORM in the first place. If that sounds ridiculously heavy duty for your simple toy app, take a look at sqlite3 for the database (which comes with Python, and which takes less work to use than coming up with a way to pickle or json all your data for persistence) and SqlAlchemy for the ORM. There's not much of a learning curve, and not much runtime overhead or coding-time boilerplate.
Sure you can implement it in Python. But there is not a single way. Quite often you have a database layer where the association class is used with two foreign keys (in your case to the primaries of Room and Guest). So in order to search you would just code an according SQL to be sent. In case you want to cache this table you would code it like this (or similarly) with an associative array:
from collections import defaultdict
class Room():
def __init__(self, num):
self.room_number = num
def key(self):
return str(self.room_number)
class Guest():
def __init__(self, name):
self.name = name
def key(self):
return self.name
def nested_dict(n, type):
if n == 1:
return defaultdict(type)
else:
return defaultdict(lambda: nested_dict(n-1, type))
room_booking = nested_dict(2, str)
class Room_Booking():
def __init__(self, date):
self.date = date
room1 = Room(1)
guest1 = Guest("Joe")
room_booking[room1.key()][guest1.key()] = Room_Booking("some date")
print(room_booking[room1.key()][guest1.key()])
I'm teaching myself Python (2.7, no previous coding experience) and I've just started dealing with classes and OOP concepts. As an exercise, I'm trying to code a very simple address book. I think I managed to understand the basics of classes and instances, but what I'm finding hard to grasp is how to further develop the level of abstraction at this point.
Trying to explain better, say I have this, which is often the base example many tutorials use to introduce classes:
class Contact(object):
def __init__(self, name, surname, phone):
self.name = name
self.surname = surname
self.phone = phone
contact1 = Contact('Mark', 'Doe', '123456789')
contact2 = Contact('Sally', 'Preston', '456789123')
So far so good, I can do many other interesting things using contact1.attribute or other methods. No problem here.
What I'm having trouble understanding is the following:
Question 1:
I don't know how many contacts I will have. How do I make a method, say, create_contact(), that makes me create a new contact and store it in a list/dict, if I don't know how many I will have? How do I call it? I can't understand how to make it so that I can create a new instance without hardcoding its name, like "contact1" etc. How do I make the line with "contact1" and "contact2" a dynamic thing?
I tried solving the problem using a list as a class variable. Something like (assuming "contact_list" already exists as a class variable):
Contact.contact_list.append(Contact('Mark', 'Doe','123456789')) # obviously I'd use raw_input instead of 'Mark' etc, but I avoided it here for readability
But I end up with a list of nameless objects, and my brain has a hard time dealing with it. I can access them with list indexes, but I'm not sure I'm on the right track here... any help would be most appreciated.
Question 2: (somewhat related, to better understand the issue)
if in the python CLI I put something like (assuming the previous block defining the class has already been run):
>>> Contact('Bob', 'Stevens', '32165497')
My understanding is that an instance of Contact() does indeed get created, with those attributes... but it has no name. How do I access it? (How do I even know it exists? Is there a way to list all existing instances relative to a certain class?)
I hope I made some sense. Thanks in advance for any kind of help.
There's nothing wrong with having "nameless" instances that get stored in a collection, but I agree that it can be hard to wrap your head around at first. ;) You don't need to know how many contacts you'll be creating, since the Python collection types are all dynamic, so you don't need to specify the size in advance, they'll grow to accomodate the data you feed them.
Here's a demo that uses your Contact class to create a simple phone book in a dictionary of lists. We save each contact both under the first name and the surname, so we can find contacts by either name. The values of the dictionary are lists so we can handle multiple people having the same name.
I added a __repr__ method to Contact to make it easy to display the contents of a Contact instance.
from collections import defaultdict
class Contact(object):
def __init__(self, name, surname, phone):
self.name = name
self.surname = surname
self.phone = phone
def __repr__(self):
return '{name} {surname}: {phone}'.format(**self.__dict__)
phonebook = defaultdict(list)
data = [
('Mark', 'Doe', '123456789'),
('Sally', 'Preston', '456789123'),
('John', 'Doe', '789123456'),
]
for name, surname, phone in data:
contact = Contact(name, surname, phone)
phonebook[name].append(contact)
phonebook[surname].append(contact)
for key, val in phonebook.items():
print(key, val)
output
Mark [Mark Doe: 123456789]
Doe [Mark Doe: 123456789, John Doe: 789123456]
Sally [Sally Preston: 456789123]
Preston [Sally Preston: 456789123]
John [John Doe: 789123456]
Another option is to make phonebook a class attribute of Contact.
Of course, to make this program really useful, we need to be able to save the phonebook to disk, and to be able to load it back in. There are various ways to do that, eg by saving the data to a CSV or JSON file, or to a pickle file. But those are topics for another question. ;)
Q1:
You can create another class that will serve as a database
class Contact(object):
def __init__(self, name, surname, phone):
self.name = name
self.surname = surname
self.phone = phone
class ContactDatabase:
def __init__(self, *args):
self.inner_list = list(args)
def add_contact(self, new_contact):
self.inner_list.append(new_contact)
# Initial contacts
contact1 = Contact('Mark', 'Doe', '123456789')
contact2 = Contact('Sally', 'Preston', '456789123')
# Creating a database
my_database = ContactDatabase(contact1, contact2)
# Adding new contacts later
my_database.add_contact(Contact('Jim', 'Miller', '111223123'))
Before i go on, let me say that i have searched the Internet for clarification before i am asking it here.I have a class
class Course(ndb.model):
tutor = ndb.StringProperty(required=True)
...
and a Student class.
I want to include in the Course class a list of Students (represented by their id)registered on the course.From my search, i came across options like StringListProperty() from this website and class ListProperty(item_type, verbose_name=None, default=None, ...) from the Google tutorial on Types and Property Classes.I am still confused as to which is the right way to do this.I need a layman's explanation and possibly a guide to where i can find a tutorial with example.Thanks
You've got a bunch of options, but probably the most straight forward is to use a ndb.KeyProperty with repeated=True. The values will be the key of your particular student. e.g.:
class Student(ndb.Model):
name = ndb.StringProperty()
class Course(ndb.Model):
students = ndb.KeyProperty(repeated=True)
def create_course(students):
"""Create a new course object and return it.
Args:
students: iterable of `Student` model instances.
"""
c = Course()
c.students = [s.key for s in students]
return c
I'm learning to work in GAE. I've read a lot of papers, all NDB docs from Google and asome questions here. I'm so used to SQL, but transform my way of think the last 20 years to NoSQL is a little hard for me, and all those different solutions gave here, drives me crazy.
I have the next simple structure:
BOOKS than can have CHAPTERS
CHAPTERS that can have VOTES
For example, Book "Sentinel" can have 3 chapters, and every chapter will have 0, 8 and 12 votes each.
In a traditional SQL I just make foreign keys from VOTES to CHAPTERS and BOOKS, and from CHAPTERS to BOOKS.
I do this for my models:
class Book(ndb.Model):
title = ndb.StringProperty(required=True)
author = ndb.StringProperty(required=True)
created = ndb.DateTimeProperty(auto_now_add=True)
# Define a default ancestor for all the books
#staticmethod
def bookKey(group='books'):
return ndb.Key(Book, group)
# Search all
#classmethod
def getAll(cls):
q = Book.query(ancestor=cls.bookKey())
q = q.order(Book.title)
books = q.fetch(100)
return books
#classmethod
def byId(cls, id):
book = Book.get_by_id(long(id), cls.bookKey())
# Get all the Chapters for a book
def getChapters(self):
chapters = Chapter.query(ancestor=self).order(Chapter.number).fetch(100)
return chapters
class Chapter(ndb.Model):
""" All chapters that a book have """
title = ndb.StringProperty(required=True)
number = ndb.IntegerProperty(default=1)
created = ndb.DateTimeProperty(auto_now_add=True)
book = ndb.KeyProperty(kind=Book)
# Search by Book (parent)
#classmethod
def byBook(cls, book, limit=100):
chapter = book.getChapters()
return chapter
# Search by id
#classmethod
def byId(cls, id, book):
return Chapter.get_by_id(long(id), parent=book)
class Vote(ndb.Model):
""" All votes that a book-chapter have """
value = ndb.IntegerProperty(default=1)
book = ndb.KeyProperty(kind=Book)
chapter = ndb.KeyProperty(kind=Chapter)
Well, my doubts are:
Is this approach correct?
The function bookKey() I've created is good to have a "Dummy Ancestor" in order to ensure that all entities are using ancestors?
Must I define in the Vote class a reference for a book and for a chapter, as it was a foreign keys (just like I think I've done)?
Is well defined the way to retrieve the chapters from a book? I mean, in the Chapter class the function byBook uses a function from the Book class. Or must I avoid to use functions from other entity to have a more clean code?
how can I retrieve all the votes for a chapter?
Which are the rigth ways to get the sum of all the votes for a especific chapter and for especific book?
Finally, I will display a single table with all my books. In the table I want to have the sum of all the votes for each book. For example:
Name | Votes
Sentinel | 30 votes
The witch | 4 votes
How can I get this info, especifically, the counted votes.
Then, clicking on the book name, I want to show all his chapters (I supose that is then when I must use the byBook function on Chapter model, right?).
Which is the GQL I need to obtain this kind of data?
Thanks in advance.
Good start. GAE's datastore is kinda confusing. Because it's schemaless, I've found that dealing with entities is much more akin to dealing with objects/data structures in memory than dealing with database tables.
Here's a few things I'd do differently:
It appears you are creating all your books under a single ancestor. Terrible idea. Screws you over in terms of performance. Unless there is some transactional operation you need to do on a group of books that's not in your current code, this is not right.
From the Book.getChapters() function it appears that you want to make a book the ancestor of a bunch of chapters. This is probably a good use of an ancestor. I don't see the code where you create chapters, but make sure the appropriate book is specified as the ancestor.
I'd simply include a vote as an attribute inside a book or chapter. There's no need to make it a separate kind that you need to issue extra queries on.
If the number of chapters per book would be limited, I'd consider using a StructuredProperty for the chapters. StructuredProperties are essentially structured data within a parent entity (Book). You'd be limited by the maximum size of the Book entity (1MB), but if it fits, it'll save you the cost of doing extra queries, since you wouldn't be querying on chapters without the appropriate book anyways.
I have a problem grasping the OOP concept when it comes to creating objects during runtime. All the educational code that I have looked into yet defines specific variables e.g. 'Bob' and assigns them to a new object instance. Bob = Person()
What I have trouble understanding now is how I would design a model that creates a new object during runtime? I'm aware that my phrasing is probably faulty since all objects are generated during runtime but what I mean is that if I were to start my application in a terminal or UI how would I create new objects and manage them. I can't really define new variable names on the fly right?
An example application where I run into this design issue would be a database storing people. The user gets a terminal menu which allows him to create a new user and assign a name, salary, position. How would you instantiate that object and later call it if you want to manage it, call functions, etc.? What's the design pattern here?
Please excuse my poor understanding of the OPP model. I'm currently reading up on classes and OOP but I feel like I need to understand what my error is here before moving on. Please let me know if there is anything I should clarify.
Things like lists or dictionaries are great for storing dynamically generated sets of values/objects:
class Person(object):
def __init__(self, name):
self.name = name
def __repr__(self):
print "A person named %s" % self.name
people = {}
while True:
print "Enter a name:",
a_name = raw_input()
if a_name == 'done':
break
people[a_name] = Person(a_name)
print "I made a new Person object. The person's name is %s." % a_name
print repr(people)
You don't store each object with a variable name. Variable names are for the convenience of a programmer.
If you want a collection of objects, you use just that - a collection. Use either a list or a dictionary containing object instances, referenced by index or key respectively.
So for example, if each employee has an employee number, you might keep them in a dictionary with the employee number as a key.
For your example, you want to use a model abstraction.
If Person is a model class, you could simply do:
person = new Person()
person.name = "Bob"
person.email = "bob#aol.com"
person.save() # this line will write to the persistent datastore (database, flat files, etc)
and then in another session, you could:
person = Person.get_by_email("bob#aol.com") # assuming you had a classmethod called 'get_by_email'
I'll try to answer as best I can here:
What you're asking about is variable variable names - this isn't in Python. (I think it's in VB.Net but don't hold me to that)
The user gets a terminal menu which allows him to create a new user and assign a name, salary, position. How would you instantiate that object and later call it if you want to manage it, call functions, etc.? What's the design pattern here?
This is how I'd add a new person (Mickey-mouse example):
# Looping until we get a "fin" message
while True:
print "Enter name, or "fin" to finish:"
new_name = raw_input()
if new_name == "fin":
break
print "Enter salary:"
new_salary = raw_input()
print "Enter position:"
new_pos = raw_input()
# Dummy database - the insert method would post this customer to the database
cnn = db.connect()
insert(cnn, new_name, new_salary, new_pos)
cnn.commit()
cnn.close()
Ok, so you want to now get a person from the database.
while True:
print "Enter name of employee, or "fin" to finish:"
emp_name = raw_input()
if emp_name == "fin":
break
# Like above, the "select_employee" would retreive someone from a database
cnn = db.connect()
person = select_employee(cnn, emp_name)
cnn.close()
# Person is now a variable, holding the person you specified:
print(person.name)
print(person.salary)
print(person.position)
# It's up to you from here what you want to do
This is just a basic, rough example, but I think you get what I mean.
Also, as you can see, I didn't use a class here. A class for something like this would pretty much always be a better idea, but this was just to demonstrate how you'd change and use a variable during runtime.
You would never do Bob = Person() in a real program. Any example that shows that is arguably a bad example; it is essentially hard-coding. You will more often (in real code) do person = Person(id, name) or something like that, to construct the object using data you obtained elsewhere (read from a file, received interactively from a user, etc.). Even better would be something like employee = Person(id, name).