Declare objects as an attribute of another object in python - python

I try to create a tree of objects / not classes. I mean i do not want to create relations between the objects in prototype level, but in instance level so the relations between the objects will be solved with the code.
Here i wrote something
class human :
def __init__ (self,Name,Surname,Gender,Age,Father,Mother) :
self.Name = Name
self.Surname = Surname
self.Gender = Gender
self.Age = Age
self.Father = Father
self.Mother = Mother
class family :
def __init__ (self,Surname,Members) :
self.Surname = Surname
self.Members = Members
def ListMembers (self) :
for member in self.Members :
print (self.Surname +' family member ' +member.Name + ' '+ member.Surname + ' is ' + member.Age + " years old ")
human1 = human( 'Mary','Walter','Female','42','Jason White','Sally White')
human2 = human('Charles', 'Walter', 'Male', '45', 'Samuel Ribbon', 'Angie Ribbon')
human3 = human('Claire', 'White', 'Female', '16', 'Charles Walter', 'Mary Walter')
WalterFamily = family('Walter',(human1,human2,human3))
WalterFamily.ListMembers
When i run this code WalterFamily.ListMembers prints nothing.
What is exact way of nesting objects in another object ?
Like i tried to do here : Nesting 3 humans inside a family and also reach to the attributes of these objects..

The last line of code is not what you want. All functions that belong to a class (like your ListMembers function) is a function stored in a variable name.
When you have what you currently have:
WalterFamily.ListMembers
You only print the function object stored at the ListMembers variable. To actually call it, you need to add parenthesis.
WalterFamily.ListMembers()

In Python everything is an object, including functions. So WalterFamily.ListMembers is just a reference to the object. To call the function you need WalterFamily.ListMembers()

Related

printing a string in object oriented programming

I'm working on a MOOC on Python Programming and am having a hard time finding a solution to a problem set. I hope you can provide some assistance.
The problem statement is:
This problem uses the same Pet, Owner, and Name classes from the previous problem.
In this one, instead of printing a string that lists a single pet's owner, you will print a string that lists all of a single owner's pets.
Write a function called get_pets_string. get_pets_string should have one parameter, an instance of Owner. get_pets_string should return a list of that owner's pets according to the following format:
David Joyner's pets are: Boggle Joyner, Artemis Joyner
class Name:
def __init__(self, first, last):
self.first = first
self.last = last
class Pet:
def __init__(self, name, owner):
self.name = name
self.owner = owner
class Owner:
def __init__(self, name):
self.name = name
self.pets = []
Add your get_pets_string function here!
Here's my code:
def get_pets_string(Owner):
result = Owner.name.first + " " + Owner.name.last + "'s" + " " + "pets are:" + Pet.name
return result
My code is getting the following error:
AttributeError: type object 'Pet' has no attribute 'name'
Command exited with non-zero status 1
Below are some lines of code that will test your function. You can change the value of the variable(s) to test your function with different inputs.
If your function works correctly, this will originally
print:
David Joyner's pets are: Boggle Joyner, Artemis Joyner
Audrey Hepburn's pets are: Pippin Hepburn
owner_1 = Owner(Name("David", "Joyner"))
owner_2 = Owner(Name("Audrey", "Hepburn"))
pet_1 = Pet(Name("Boggle", "Joyner"), owner_1)
pet_2 = Pet(Name("Artemis", "Joyner"), owner_1)
pet_3 = Pet(Name("Pippin", "Hepburn"), owner_2)
owner_1.pets.append(pet_1)
owner_1.pets.append(pet_2)
owner_2.pets.append(pet_3)
print(get_pets_string(owner_1))
print(get_pets_string(owner_2))
Could you please offer some guidance on what I'm not doing right with my code?
In your code, the name is an instance variable of Pet class. So, to access name of Pet you need an instance of Pet class. But in your code in the Pet.name, the Pet refers to the class and as there is no class variable name in Pet class, the above error is displayed.
To fix this, you can use the member pets of Owner class representing list of Pet object. So in the get_pets_string() you can iterate over pets member of Owner and print names of all the pets.
So after change to get_pets_string(), it will look like -
def get_pets_string(owner):
result = owner.name.first + " " + owner.name.last + "'s pets are: " + ", ".join(p.name.first + " " + p.name.last for p in owner.pets)
return result
Here I have used join() to show the name of all the pets separated by comma

Python deleting a class object in run time

This is my code for reference:
class Manager(Employee):
def __init__(self, first, last, position, salary):
super().__init__(first, last, position)
self.salary = salary
def getinfo(self):
return self.first, self.last, self.position, self.salary
def give_raise(self, employee):
if type(employee) == type(Teller_1):
employee.hourly = int(employee.hourly * 1.10)
else:
employee.salary = int(employee.salary * 1.10)
def fire_employee(self, employee):
if type(employee.first) == type(Branch_manager) or type(employee) == type(Bank_executive):
print ("you cannot fire someone in an equal or higher position")
else:
print ("you have successfully fired " + str(employee.first) + " " + str(employee.last))
del employee
print (Analyst_1)
Analyst_1 = SalaryEmployee('Bob', 'Dun', 'Account Analyst', 40000)
When I put in this code:
Branch_manager.fire_employee(Analyst_1)
I want it to remove the object "Analyst_1". However, all it is doing is removing the reference variable "employee" and not the object itself.
How can I remove the actual object itself and not just the reference variable?
You can delete a name using the del keyword or the delattr built-in function, but you can't delete an object. (Objects don't get deleted, they get garbage collected when no names refer to them anymore.)
If your method looks like:
def fire_employee(employee):
...
and you call it like
fire_employee(Analyst_1)
then the object that the name Analyst_1 refers to will be the same object that the name employee refers to. So even if you delete one of those names, the object itself will still exist as long as the other name still references it.
You can delete the name from the global namespace, if you know what namespace it is and what name it is:
def fire_employee(employee_name):
module_object = sys.modules[__name__]
delattr(module_object, employee_name)
which you would call like this instead:
# Note that we pass a *string*, "Analyst_1", and not the *object*.
fire_employee('Analyst_1')
But if you're going to go that route, you'd be better off keeping the employee name to object mapping in its own data structure, likely a dict object as was already suggested.

Random values in an instance of a class, that are not saved

I am new to python and want to write a simple text adventure game. The player enters a tavern and interacts with the guests. The game takes place in a fantasy setting, where there are multiple races. I want to randomly generate each guest and then interact with them in the tavern. Here is my simplified code:
import random
class guest:
def __init__(self,race,name,mood):
self.race = race
self.name = name
self.mood = mood
def humannames():
human_names_choice = ('Mark','Joe','Bill')
return random.choice(human_names_choice)
def orcnames():
orc_names_choice = ('Ug','Orok','Ushnar')
return random.choice(orc_names_choice)
def humanmoods():
human_moods_choice = ('entertained','disgusted','pleased')
return random.choice(human_moods_choice)
def orcmoods():
orc_moods_choice = ('drunk','pissed off','angry')
return random.choice(orc_moods_choice)
guest_human = guest('human',humannames(),humanmoods())
guest_orc = guest('orc',orcnames(),orcmoods())
allguests = [guest_human,guest_orc]
guest1 = random.choice(allguests)
print('You meet a ' + guest1.race + ' named ' + guest1.name + '. He seems ' + guest1.mood)
So far so good. With this system i can add many more races,names etc. later.
My problem is the following:
It is logical, that guest1.name and guest.race never change. If i print the last statement 5 times in a row, i will get the same results, because the values are set at the start. This is good for me, because those things should never change. With guest1.mood however it is more complicated. A tavern guest doesnt always have the same mood, it changes over time.
Question: How can i keep guest1.name and guest.race static but get a new random mood everytime the player meets the same guest again later?
Thanks in advance!
You can add a change_mood method to your guest class. This means that you can change the mood whenever you want.
class guest:
def __init__(self,race,name,mood):
self.race = race
self.name = name
self.mood = mood
def change_mood(self):
self.mood = random.choice(('entertained','disgusted','pleased'))
Then you can change the mood like this.
print('You meet a ' + guest1.race + ' named ' + guest1.name + '. He seems ' + guest1.mood)
guest1.change_mood()
print('You meet a ' + guest1.race + ' named ' + guest1.name + '. He seems ' + guest1.mood)
This will always change the mood to a human mood, which is not ideal for orcs. To make this easier for different races, you could make two subclasses of guest: one for humans, and one for orcs. I would organise it like this:
class Guest:
def __init__(self):
self.name = random.choice(self.names)
self.mood = random.choice(self.moods)
def change_mood(self):
self.mood = random.choice(self.moods)
class Human(Guest):
race = 'human'
names = ('Mark', 'Joe', 'Bill')
moods = ('entertained', 'disgusted', 'pleased')
class Orc(Guest):
race = 'orc'
names = ('Ug', 'Orok', 'Ushnar')
moods = ('drunk',' pissed off', 'angry')
You can then use the classes like this:
guest1 = Orc()
print('You meet a ' + guest1.race + ' named ' + guest1.name + '. He seems ' + guest1.mood)
Edit: another way would be to store all of your race data in one big data structure, and then specify the race as an argument to the Guest class.
class Guest:
races = {
'human': {
'names': ('Mark', 'Joe', 'Bill'),
'moods': ('entertained', 'disgusted', 'pleased'),
},
'orc': {
'names': ('Ug', 'Orok', 'Ushnar'),
'moods': ('drunk',' pissed off', 'angry'),
},
}
def __init__(self, race):
self.race = race
self.name = random.choice(self.races[race]['names'])
self.mood = random.choice(self.races[race]['moods'])
def change_mood(self):
self.mood = random.choice(self.races[self.race]['moods'])
Also, instead of storing the race data in the class, you could store it in a separate JSON file or something, and then load the data from the file in the __init__ method.

Create an instance of a class and rename it based on user input

I have created a (somewhat) conversational bot and I want it to be able to create a model of the people whose names it hears. I wish to do this by having it create a new instance of my "person" class, and have that class instance named as that person (as in Bob, Alice, etc.) I've been at this all night, thought I had it because it said I had created the instance, but when trying to reference said instance of the class, it tells me that the name 'Bob' is not defined:
properNouns = [word for word,pos in taggedSent if pos == 'NNP']
if properNouns:
npn = str(properNouns)
print(npn) # ['Bob']
npn = re.sub('[\[\]\,\']', '', npn)
print(npn) # Bob
newPerson = Self(npn,'','','','','','','','','','','','','','') # Put "Bob" as the fName
newPerson.__name__ = npn # Change the instance name to "Bob" (well, try anyway)
print(str(newPerson.__name__) + " was created!") # Bob was created!
print(Bob.fName + " is the first name") # NameError: name 'Bob' is not defined
My base class is as follows:
class Self(): # A starter concept of a Host's concept of Self/Me
def __init__(self, fName, lName, DoB, job, hColor, eColor, sex, homeTown, homeState, whatIHave):
self.fName = fName
self.lName = lName
self.DoB = DoB
self.job = job
self.hColor = hColor
self.eColor = eColor
self.sex = sex
self.homeTown = homeTown
self.homeState = homeState
self.whatIHave = whatIHave
def getFullName(self):
fullName = str(self.fName) + ' ' + str(self.lName)
return fullName.title()
I can successfully manually create an instance and subsequently call up its attributes via dot notation if I hard-code it in advance, but that is not how this needs to work (If in the conversation I say I met with Bob, I need the bot to create a new instance of the Self class named Bob.)
mySelf = Self('Bob','Jones',"Coder",'19730101',black','brown','F','Boston','Massachusetts','a Jeep Wrangler')
And if I subsequently print a Bob.fName, I get Bob....
I can do some fairly decent coding but this is a relatively new area for me, and it may be that I've seen what is the answer but simply don't understand what I'm seeing well enough to know it's what I need, so apologies. I've seen many posts with very similar titles, but they do not seem to have the answer for what I am looking to do here, which seems simple to me: If I create a new "Self" (newSelf = Self), then I want to rename newSelf to "Bob".
Alternatively, and I would think easier, would be to have the new Self created with the proper name to begin with but I can't find a way to take a variable containing the name and make that name = the new Self...
Thanks for your help. I've been at this for over six hours now.

Accessing method variables of one class in another python class

I have started learning Object Oriented concepts in python. I have got this sample code below:
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
class School(object):
students = []
def __init__(self, name):
self.name = name
def add_student(self, student):
self.students.append(student)
def show_students(self):
print("{0} Student Roster".format(self.name))
for s in self.students:
print("{0}: {1}".format(s.name, s.age))
my_school = School("Quora University")
first_student = Student("Rongan Li", 20)
second_student = Student("Jason Kane", 20)
my_school.add_student(first_student)
my_school.add_student(second_student)
my_school.show_students()
Question:
In the def show_students method of School class how they are accessing the construct variables of class student without instance of that class?
first_student = Student("Rongan Li", 20)
second_student = Student("Jason Kane", 20)
These lines create object of student class ,first_student which has name 'Rongan Li' and age '20'.
second_student which has name 'Jason Kane' and age '20'
Now, you add these 2 objects to the list.
my_school.add_student(first_student)
my_school.add_student(second_student)
Now, when you iterate in the list
for s in self.students:
print("{0}: {1}".format(s.name, s.age))
's' goes to first element of list, and since it is an object of class Student , 's' becomes object of student class. Now, since 's' is first element in the list and on first place you added 'Rongal Li' and 20 . So, s has 2 properties name and age. When you do s.name , it prints 'Rongal Li' and s.age prints 20
Then it goes to next element and same process is repeated.
in the method show_students there's a for loop :
for s in self.students:
print("{0}: {1}".format(s.name, s.age))
it loops over the list of students added by method add so inside the loop the variable "s" represent an instance of student class so s.name is a legit way of accessing an instance variable by using an instance of the class
The students are added to School.students list via the add_student method.
my_school.add_student(first_student)
my_school.add_student(second_student)
These two lines add two references to the School.students list in my_school. So now the list has two references pointing at first_student and second_student.
You can think of the list in my_school at this point as
students = [Pointer to first_student, Pointer to second_student]
When you call my_school.show_students(), my_school.students list (the list above) is accessed and through the references to first_student and second_student in the list, you access the original first_student object and second_student object and can then retrieve their properties.

Categories

Resources