Class import and assignment in Python - python

If I am creating a class below, can someone please explain the proper way to create the instance and also pass in the arguments. I though that I would be able to pass in the initial arguments at time of initiation but cannot seem to get this to work. Below is an example of the class:
Class Course(object):
"""
Represents a University course
"""
def _init_(self, name, teacher, description):
self.name = name
self.teacher= price
self.description = description
def _str_(self):
return "{name} ({desc}): {teacher:}".format(name=self.name,
desc=self.description, teacher=self.teacher)
So in my program I'd like to create an instance which I though I do by using something like class = Course().
But isn't there a way to initiate the 3 variables at the same time? Something along the lines of class('Math101', 'Dr. Know Nothing', 'Learning is Fun') ?
Then I can just print class and get my desired output string as defined from within the class? I might be missing an import somewhere which is also confusing to me if I need to import modules or with a class all I need to do is the initial class = Course() ?

You have to declare special methods with double underscores: __init__, not _init_. And then, when creating an object, you have to pass the arguments like: course1 = Course(...parameters...):
class Course(object):
"""
Represents a University course
"""
def __init__(self, name, teacher, description):
self.name = name
self.teacher = teacher
self.description = description
def __str__(self):
return "{name} ({desc}): {teacher:}".format(name = self.name,
desc = self.description, teacher = self.teacher)
course1 = Course('Math101', 'Dr. Know Nothing', 'Learning is Fun')
print course1
Output:
Math101 (Learning is Fun): Dr. Know Nothing
Notes:
The Python keyword to create a class is class, not Class. Python is case-sensitive for keywords.
You were assigning price to self.teacher, which would lead in an error because price is not declared anywhere. I think it's just a typo. You may use self.teacher = teacher instead.
You must not use Python keywords (reserved names) as name of variables, because if you did, you would be hiding those keywords, which would lead into problems.

First things first, you need to double your underscores:
def __init__(self, ...):
// whatever
def __str__(self, ...):
// whatever
and lowercase your Class: class Course instead of Class Course.
Now you can use your class like this:
course = Course('Math101', 'Dr. Know Nothing', 'Learning is Fun')
print course

Related

Class within a class (as attribute) to call a method of the class that contains it

I am in the situation where I need a class that is within another (as an attribute) to communicate with the class that contains it, however, I cannot wrap my head around how to do it.
Take this situation as an example: There is a class HighSchoolClass that contains a list of Students that belong to that class, and HighSchoolClass has a method foo rearranging how the students are sited or whatever. But then, each student has the capability of asking if a rearranging can be made. So it would need to call the method for rearranging the class.
# Singelton
class HighSchoolClass:
def __init__(self):
self.list_of_students = # A list of instances of Student
self.profesor = ...
def rearrange_class():
# do something
class Student:
def ask_for_rearrange():
# Needs to call rearrange_class() of the class he is in.
Is there any way of do this (ideally just calling it somehow)? Mind that rearrange_class() is not static. If it helps, the HighSchoolClass would be a singelton.
Typically, you would explicitly give each Student a reference to the HighSchoolClass that they belong to. A simple example might look like
class Student:
def __init__(self):
self.class_ = None
def add_class(self, class_):
self.class_ = class_
class HighSchoolClass:
def __init__(self):
self.list_of_students = []
def add_student(self, student):
self.list_of_students.append(student)
class Registrar:
def add_student_to_class(self, student, class_):
class_.add_student(student)
student.add_class(class_)
Note the use of a third class to both the student and the class. Otherwise, it's not obvious whether a student should be responsible for updating each class they join, or whether each class should update their students.
the_class = HighSchoolClass()
s1 = Student()
s2 = Student()
r = Registrar()
r.add_student_to_class(s1, the_class)
r.add_student_to_class(s2, the_class)
Now, each class and student has a reference to the other to be used as needed.

What does Django's #property do?

What is #property in Django?
Here is how I understand it: #property is a decorator for methods in a class that gets the value in the method.
But, as I understand it, I can just call the method like normal and it will get it. So I am not sure what exactly it does.
Example from the docs:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
def baby_boomer_status(self):
"Returns the person's baby-boomer status."
import datetime
if self.birth_date < datetime.date(1945, 8, 1):
return "Pre-boomer"
elif self.birth_date < datetime.date(1965, 1, 1):
return "Baby boomer"
else:
return "Post-boomer"
#property
def full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
What is the difference of if it is there vs if it isn't?
As you see, the function full_name returns a string with the persons first and last name.
What the #property decorator does, is declare that it can be accessed like it's a regular property.
This means you can call full_name as if it were a member variable instead of a function, so like this:
name = person.full_name
instead of
name = person.full_name()
You could also define a setter method like this:
#full_name.setter
def full_name(self, value):
names = value.split(' ')
self.first_name = names[0]
self.last_name = names[1]
Using this method, you can set a persons full name like this:
person.full_name = 'John Doe'
instead of
person.set_full_name('John Doe')
P.S. the setter above is just an example, as it only works for names that consist of two words separated by a whitespace. In real life, you'd use a more robust function.
In some languages users are encouraged to make attributes private and create public getter and setter methods, e.g. in some made up Python-like language with private and public:
class Foo:
private bar
public get_bar(bar):
return self.bar # or look it up in a database
# or compute it on the fly from other values
# or anything else
public set_bar(new_bar):
self.bar = new_bar
The argument is about providing a stable interface. If you want to change the inner workings of your class, e.g. to look it up from a database or compute it, users of the class won't have to change anything; they just keep calling the getter and setter.
In Python we don't really have private attributes, and we want simple syntax. So we flip it: programmers often directly access an object's attributes. But what if you want to change the internal behaviour? We don't want to change the class' interface.
#property lets you change how bar works internally without changing the external interface. Users of the class can still access foo.bar, but your internal logic can be completely different:
class Foo:
def __init__(self, bar):
self.bar = bar
def main():
f = Foo()
print(f.bar)
# Later we can change to something like this without breaking other code
class Foo:
def __init__(self, bar):
self.save_bar_to_database(bar) # Or anything else
#property
def bar(self):
return self.load_bar_from_database()
It is a simple way, where you can get variables in the table and provide another variable which can be used directly as it was a variable.
#property
def total(self):
total_price = self.products.price_each * self.quantity_prt
return total_price
such as abouve function you can get number of products and price and ue a property and make a variable of total price.

class and methods in python. introduction in oop

class Person:
def __init__(self, name):
"""Make a new person with the given name."""
self.myname = name
def introduction(myname):
"""Returns an introduction for this person."""
return "Hi, my name is {}.".format(myname)
# Use the class to introduce Mark and Steve
mark = Person("Mark")
steve = Person("Steve")
print(mark.introduction())
print(steve.introduction())
its suppose to produce
"Hi, my name is Mark." or "Hi, my name is Steve."
but instead it produces
"Hi, my name is undefined."
It should be printing the object's representation in memory (something along the lines of Hi, my name is <__main__.Person object at 0x005CEA10>).
The reason is that the first argument of a method is expected to be the object that the method is called upon.
Just like you have def __init__(self, name): you should have def introduction(self, myname):.
Then you will encounter another problem, as introduction now expects an argument myname which you don't provide. However, it is not needed now since you have access to self.myname.
class Person:
def __init__(self, name):
"""Make a new person with the given name."""
self.myname = name
def introduction(self):
"""Returns an introduction for this person."""
return "Hi, my name is {}.".format(self.myname)
# Use the class to introduce Mark and Steve
mark = Person("Mark")
steve = Person("Steve")
print(mark.introduction())
print(steve.introduction())
Will output
Hi, my name is Mark.
Hi, my name is Steve.
You need to declare introduction() -> introduction(self) as an instance method (by passing in self) to be able to access the instance variable self.myname.
class Person:
def __init__(self, name):
"""Make a new person with the given name."""
self.myname = name
def introduction(self):
"""Returns an introduction for this person."""
return "Hi, my name is {}.".format(self.myname)
Sample output:
# Use the class to introduce Mark and Steve
mark = Person("Mark")
steve = Person("Steve")
print(mark.introduction())
print(steve.introduction())
>>> Hi, my name is Mark.
>>> Hi, my name
Please note however, that the first parameter in a function within a class is reserved for either a class, or object to pass itself to (unless a #staticmethod tag is applied to the method, then the first implicit parameter is not passed; which essentially behave as module methods).
Also keep in mind that self is not a reserved word, so you could name it anything (even though self is PEP convention). The below example executes the same output as the example above, and is semantically the same.
def introduction(myname):
"""Returns an introduction for this person."""
return "Hi, my name is {}.".format(myname.myname)
9.3.5. Class and Instance Variables
Your problem is that your giving your introduction method the parameter myname, but never supplying it with a valid argument.You can simply do:
mark = Person(" Mark")
steve = Person(" Steve")
print(mark.introduction(mark.myname))
print(steve.introduction(steve.myname))
your giving the introduction method, the variable from your class myname.
But the above is not even necessary. Since your initializing your name variable in the __init__ method of your class, it is like a global variable. So you can simply say:
class Person:
def __init__(self, name):
"""Make a new person with the given name."""
self.myname = name
def introduction(self):
"""Returns an introduction for this person."""
return "Hi, my name is{}".format(self.myname)
# Use the class to introduce Mark and Steve
mark = Person(" Mark")
steve = Person(" Steve")
print(mark.introduction())
print(steve.introduction())

Python understanding OOP, inheritance

I solve this problem:
Develop an application which operates with next types:
Person (field Name, method ShowData())
Student (field Education)
Worker (field WorkPlace)
Classes Student and Worker are derived from class Person.
Class Academy in it's container collects Students and Workers and shows Name, Education or WorkPlace for all persons in method ShowAll().
We can add new persons to Academy by calling method AddPerson().
Which hierarchy of classes is the best
for solving this problem?
Code should include inheritance and use collections.
This is my solution, but i don't know how to realize method AddPerson:
class Academy(object):
theWholeList = []
#staticmethod
def showAll():
for obj in Academy.theWholeList:
if isinstance(obj,Student):
print obj.name+' - '+obj.edu
elif isinstance(obj,Worker):
print obj.name+' - '+obj.wplace
class Person(Academy):
def __init__(self,name):
self.name = name
super(Person, self).theWholeList.append(self)
def showData(self):
return vars(self)
class Student(Person):
def __init__(self, name, edu):
super(Student, self).__init__(name)
self.edu = edu
class Worker(Person):
def __init__(self, name, wplace):
super(Worker, self).__init__(name)
self.wplace = wplace
Maybe Academy must inherit Person and method AddPerson will be like that:
def add(self,name):
super(Academy,self).__init__(name)
first thing:
class Academy(object):
theWholeList = []
#staticmethod
def showAll():
for obj in Academy.theWholeList:
if isinstance(obj,Student):
print obj.name+' - '+obj.edu
elif isinstance(obj,Worker):
print obj.name+' - '+obj.wplace
you do not need to have Academy's method showAll() be a static method, as on your design the Academy is legitimate to be a singleton, i.e. a class having a single instance.
Also theWholeList is a very bad name for a list. Because you know it is a list, as you're assigning it a list. The name shall describe its semantic, i.e. the kind of things it contains, what it is used for.
You should rewrite it as follows:
class Academy:
def __init__(self):
self.person_list = []
def show_all(self):
for item in self.person_list:
item.show_data()
And you would instanciate it once:
academy = Academy()
Then the following:
class Person(Academy):
def __init__(self,name):
self.name = name
super(Person, self).theWholeList.append(self)
is bad design: in object oriented programming you should think about encapsulating data. Here you're making the assumption that Person knows the internals of Academy. And what if you decide to change Academy's implementation so theWholeList is renamed? Or switched into a dict()? This should be transparent to the "user" of the class Academy. A better design should be:
class Academy:
... # cf earlier
def add_person(self, person):
self.person_list.append(person)
class Person(Academy):
def __init__(self,name):
self.name = name
def show_data(self):
print("My name is: {}".format(name))
So you can use it as follows:
person_a = Person("John Doe")
person_b = Person("Jim Smith")
academy.add_person(person_a)
academy.add_person(person_b)
And finally you're wondering:
Maybe Academy must inherit Person
Most of the time, subclassing is the wrong answer of a wrong question. You need to subclass when you want to extend or specialize behaviour of a class. A classical example would be:
class Animal:
def noise(self):
raise NotImplementedError # virtual method
class Duck(Animal):
def noise(self):
print("quack")
class Cat(Animal):
def noise(self):
print("meaw")
So in your case, you have a class person that implements show_data, and what you want is to extend the behaviour, for worker and student:
class Worker(Person): # a worker _is_ a person!
def __init__(self, name, unit):
# left as an exercise to the OP
def show_data(self):
# left as an exercise to the OP
class Student(Person):
def __init__(self, name, promo):
# left as an exercise to the OP
def show_data(self):
# left as an exercise to the OP
I won't get into much more details here, as I suppose you have a teacher you can ask more about the comments I made. But at least you tried, made some mistakes (AND MISTAKES ARE GOOD!). But I'm not giving you a full answer, my only goal here is to set you up in the right mind set to make your code a better design!
I hope this helps!
You want to be able to add people:
>>> academy = Academy()
>>> academy.add(Person('Pete'))
>>> academy.showAll()
Name: Pete
>>> academy.add(Student('Taras', 'Higher'))
>>> academy.showAll()
Name: Pete
Name: Taras, Education: Higher
>>> academy.add(Worker('riotburn', 'StackOverflow')
>>> academy.showAll()
Name: Pete
Name: Taras, Education: Higher
Name: riotburn, Workplace: StackOverflow
showAll needs to iterate over all people calling ShowData on them. This will be implemented differently for each type.
class Academy(object):
def __init__(self):
self.people = []
def add(self, person):
self.people.append(person)
def showAll(self):
for person in self.people:
person.ShowData()
Where for example, Worker will implement ShowData as:
def ShowData(self):
print 'Name: ' + self.name + ', Education:' + self.edu

Using certain attributes of an object to make other objects in a different class

For a program that creates a timetable for a doctor(specialist) I want to use certain attributes of an object created by a different class to be used in the class that makes the timetable for the doctor.
class makePatient(object):
def __init__(self,name,room):
self.name = name
self.room = room
def getPatient(self):
print(self.name)
print(self.room)
class makeSpecialist(object):
def __init__(self,name,specialization,timetable):
self.name = name
self.specialization = specialization
self.timetable = timetable
def getSpecialist(self):
print(self.name)
print(self.specialization)
print(self.timetable)
class makeAgenda(object):
def addAgenda(self):
self.timetable.append()
#I want to append the name of the patient I have defined here.
print(self.timetable)
patient1 = makePatient("Michael","101")
specialist1 = makeSpecialist("Dr. John","Hematology",[])
What do I do now, to make sure that the name "Michael" gets added to the list [] of specialist Dr. John?
Thanks in advance, I will provide further details if necessary!
I think another approach would be better; you can put the whole makePatient object into the timetable for the specialist:
specialist1 = makeSpecialist("Dr. John", "Hematology", [patient1])
Now you can access the names and other attributes of the patients in a specialist's timetable:
for patient in specialist1.timetable:
print(patient.name)
You can also define a __repr__ method to tell Python how to display an object, rather than the current getPatient:
class makePatient(object):
# ...
def __repr__(self):
return "{0} (room {1})".format(self.name, self.room)
Now when you print the whole timetable:
>>> print(specialist1.timetable)
You get the necessary information:
[Michael (room 101)]
Note also that the classes should probably be called, simply, Patient, Specialist and Agenda; the make is implied.
Finally, you will get errors in makeAgenda.addAgenda as, without an __init__, self.timetable doesn't exist for a makeAgenda object, and an empty append() doesn't do anything anyway.
Classes are often used to represent entities and operations allowed on them, include constructing, or making, new instances of them. Therefore, your classes would be better named simplyPatient, Specialist, andAgenda. The name of the method that constructs a new instance of any class in Python is always__init__().
That said, after creating aPatientand aSpecialistyou could then add patient instances to the specialist's timetable/agenda by passing it to aSpecialistmethod specifically designed for that purpose. In other words, a Specialist "has-a" Agenda instance namedtimetableand to which patients can be added via an appropriately namedadd_to_timetable()method.
Here's what I mean -- note I've modified your code to follow PEP 8 -- Style Guide for Python Code guidelines which I also suggest that you follow:
class Agenda(object):
def __init__(self):
self.events = []
def append(self, event):
self.events.append(event)
class Patient(object):
def __init__(self, name, room):
self.name = name
self.room = room
def get_patient(self):
print(self.name)
print(self.room)
class Specialist(object):
def __init__(self, name, specialization):
self.name = name
self.specialization = specialization
self.timetable = Agenda()
def add_to_timetable(self, patient):
self.timetable.append(patient)
def get_specialist(self):
print(self.name)
print(self.specialization)
print(self.timetable)
specialist1 = Specialist("Dr. John", "Hematology")
patient1 = Patient("Michael", "101")
specialist1.add_to_timetable(patient1)
I'm not too sure what you're trying to accomplish here with method that just print values or with the makeAgenda class, but here's how you can get Michael in Dr. John's list:
specialist1.timetable.append(patient1.name)

Categories