How to print class variables in a list - python-3.x

So I am very new to coding and started with python, I am trying to build a class in a program that puts together a DnD party by randomising their attributes. So far I can get the program to initialise instances of the party members and just give the user a prompt on how many of the hero's to choose from they would like in their party. My issue is that after setting the lists up and getting everything in place. I am unable to print any of the attributes of the individual heros. Regardless of whether I am calling them from within the lists or if I am directly trying to print them. I have tried using __str__ to create strings of the attributes but I am clearly missing something. Any help would be greatly appreciated.
import random
class Party:
def __init__(self, name="", race="", alignment="", class_=""):
self.name = name
while name == "":
name = random.choice(names)
# print(name)
self.race = race
while race == "":
race = random.choice(races)
# print(race)
self.alignment = alignment
while alignment == "":
alignment = random.choice(alignments)
# print(alignment)
self.class_ = class_
while class_ == "":
class_ = random.choice(classes)
# print(class_)
def character_stats(self):
return "{} - {} - {} - {}".format(self.name, self.race, self.class_, self.alignment)
Each attribute pulls a random value from a list. My format statement is the latest attempt to get the values of the attributes to print rather than the object/attributes instead.
I apologise if any of the terminology is wrong, very very new to this

You are not assigning anything else but the input, (in this case being an empty string "" to the attribuytes. In your minimal example you have this constructor:
class Party:
def __init__(self, name=""):
self.name = name
while name == "":
name = random.choice(names)
After you randomly assign a new name from names, you should assign it to self, otherwise the local variable just goes out of scope when the __init__ method finishes. This code snippet should work:
class Party:
def __init__(self, name=""):
while name == "":
name = random.choice(names)
# Now we assign the local variable as
# an attribute
self.name = name

Related

How can I change values using the same object?

So I will have to finish a half-done code to get the desired output.
the half-done code goes as follows AND I AM NOT ALLOWED TO CHANGE THIS CODE:
class Wadiya():
def __init__(self):
self.name = 'Aladeen'
self.designation = 'President Prime Minister Admiral General'
self.num_of_wife = 100
self.dictator = True
the desired output goes as follows:
Part 1:
Name of President: Aladeen
Designation: President Prime Minister Admiral General
Number of wife: 100
Is he/she a dictator: True
Part 2:
Name of President: Donald Trump
Designation: President
Number of wife: 1
Is he/she a dictator: False
Now to get this output, I will have to use the same object which is wadiya in this case to change the values of the instance variables. Then print if it affected the previous values of Part 1. If it did, I'll have to print 'Previous information lost' otherwise I'll have to print 'No, changing had no effect in previous values.'
Now my question is, how can I change the values of the instance variables using the same object? This is what I've done, but I don't think this what the question has asked me to do. What do you think? Am I on the right track? Here's my approach:
class Wadiya():
def __init__(self):
self.name = 'Aladeen'
self.designation = 'President Prime Minister Admiral General'
self.num_of_wife = 100
self.dictator = True
def my_method(self):
print('Name of the President:', self.name)
print('Designation:', self.designation)
print('Number of wife:', self.num_of_wife)
print('Is he/she a dictator:', self.dictator)
def change_values(self, name, designation, num_of_wife, dictator):
self.name = name
self.designation = designation
self.num_of_wife = num_of_wife
self.dictator = dictator
print('Part 1:')
wadiya = Wadiya()
wadiya.my_method()
print('Part 2:')
wadiya = Wadiya()
wadiya.change_values('Donald Trump', 'President', 1, False)
wadiya.my_method()
Question is a bit ambiguous why would you want to change all values of an instance. If you want you can reassign new instance to same variable just pass arguments to init instead of change_method
if you want default values to class then you don't need to do init and then change values.
def __init__(self, name: str = None): # None is default value
self.name: str = name if name else 'Aladeen'
For some reason if you want to change values of instanced objects then do
wadiya.name = 'Donald'
what you are doing will work, but generally not suggested

How can I create aliases of objects that inherit only a particular attribute

I'm making a program in python where the user can add a name and number to a list.
I went with saving the entries in a class with 2 attributes and saving the instances of the class as objects in a list:
class NewEntry:
def __init__(self):
self.name = ""
self.number = ""
entry = NewEntry()
entry.name = userinput[1]
entry.number = userinput[2]
entrylist.append(entry)
I'm now trying to add a function called alias, that will save an entry under a new name. The alias is supposed to be connected to the original entry in such a way that changing the number of one of them will change the number of every corresponding alias to the same value.
Here is the code for my attempt at this:
for key in entrylist:
if key.name == userinput[1]:
entry = key
entry.name = userinput[2]
entrylist.append(entry)
This does not work as intended. When creating a new alias, it also changes the .name of key, the I'm attempting to only inherit the number-attribute from.
I've also attempted the following method:
for key in entrylist:
if key.name == userinput[1]:
entry = NewEntry()
entry.name = userinput[2]
entry.number = key.number
entrylist.append(entry)
TL;DR:
I want to be able to create copies of an object where the .number-attribute is the same across all aliases. I want the name to be different in all of these objects, but the number to stay the same. A change in the number of one of the aliases would affect the others as well.
You could link them up by adding an alias_of attribute to signify what a name is an alias of.
If you pair it up with a property for your number attribute then you control which object actually gets set.
class NewEntry:
# I added the attributes as constructor
# arguments since you're setting them anyway
def __init__(self, name='', number=None, alias_of=None):
self.name = name
# since we want self.number to be a property
# it is common practice to use a _ to signify
# that an attribute is private
self._number = number
# here alias will refer to the instance it's
# an alias of. It defaults to None
# or not an alias
self.alias_of = alias_of
# giving a method a #property decorator
# makes it get the attribute from here
# That way you control which number it's getting
#property
def number(self):
if self.alias_of:
return self.alias_of.number
else:
return self._number
# The same is true if you give it a setter
# method. It controls which instances number
# that you set
#number.setter
def number(self, value):
if self.alias_of:
self.alias_of.number = value
else:
self._number = value
entry = NewEntry('my name', number=1)
entry2 = NewEntry('my name 2', number=2)
# here we say that entry3 is an alias of entry
entry3 = NewEntry('my other name', alias_of=entry)
print(entry.number)
print(entry2.number)
# and here entry3 is actually setting entry
# 1's number attribute
entry3.number = 3
print(entry.number)

Dynamic Python Dataclass

I need to minimize the response footprint of an API. One way we are doing that is eliminating attributes that are null. Which introduces the challenge to create a dataclass that I can build dynamically.
I have managed to get the dynamic class created and it contains the data I need (viewing in log). But, I have not been able to get it inserted into the Parent Class. ParentClass portion is Emtpy with this logic.
#dataclass
class VR: pass
#dataclass
class ResultParent:
validationResult: VR
matchCandidate: List[matchCandidates] = field(default_factory=list)
#create and pop dynamic class
vr = VR()
if valres.matchStatusCode is not None:
vr.matchStatusCode = valres.matchStatusCode
if valres.matchStatusReason is not None:
vr.matchStatusReason = valres.matchStatusReason
...
#This pprint works and the attr/values are what we want
pprint(vars(vr))
#Create ParentClass
obj = ResultParent([vr],[])
# The result of the above command is empty
#Code then continues on to populate matchCandidates and then the ParentClass - no issues there
I was able to accomplish this. I added a setattr that only added the attr if it was not NONE. Found it in this post. Which was the desired result.
#dataclass
class VR:
def __setattr__(self, name, value):
if value is not None:
self.__dict__[name] = value
#dataclass
class ResultParent:
validationResult: VR
matchCandidate: List[matchCandidates] = field(default_factory=list)
vr = VR()
vr.matchStatusCode = p.get('ValAddrStatus')
vr.matchStatusReason = p.get('ValAddrStatusCode')
...
obj = ResultParent([vars(vr)],[])

Accessing a Single Variable from Another Class (Python)

So, I'm having trouble figuring out how to best structure my Python code. I have a short program using classes, which I've recreated in an example below:
prof1 = Professor()
prof2 = Professor()
professor_list = [prof1, prof2]
class Professor:
def __init__(self):
self.name = ""
self.department = ""
self.course = ""
self.students = []
class Student:
def __init__(self):
self.name = ""
self.activities = []
So basically, I have a list of objects which are instances of the Professor class. Each Professor object also contains a list of Student objects, each of which is an instance of the Student class. I want each Student to also be able to access the course variable from its corresponding Professor (the Professor object with that Student in its list), but I wasn't sure what the neatest way to do this would be.
I considered having Student inherit from Professor, but that seemed sloppy, since I don't actually want to inherit all of the variables and functionality from Professor. For example, Professor's department variable has nothing to do with a Student object, and I don't want Students to have a department attribute. Also, Student isn't a sub-type of Professor, which is what I would associate with inheritance.
I also thought of manually adding the course information to each Student as an attribute, but that didn't seem right either. In the structure I want, the course would be a unique attribute of the Professor, and the various students would be associated with the Professor. All the students that would need to access the course variable are in the Professor's student list - so shouldn't there be a neater way of allowing them to use it than adding it manually to each student?
Here's one more idea: I might include a reference to the corresponding Professor class in each Student, and access the variable that way. Would this be bad practice?
I'd really appreciate any help you can give me with this.
You could go the route of the reference to the Professor, but I think the easiest way would be to create an add_student method which adds the Student to the corresponding Professor's list, as well as marks the course on the Student, so you don't have to do this manually and you can avoid a circular reference (which also is unnecessary because if you're marking the Professor reference on the Student just to get the course attribute, then you may as well just mark the course attribute directly):
class Professor:
def __init__(self):
self.name = ""
self.department = ""
self.course = ""
self.students = []
def add_student(self, student):
self.students.append(student)
student.course = self.course
class Student:
def __init__(self):
self.name = ""
self.activities = []
self.course = None
Alternatively, you could add a method to the Professor which checks if the Student belongs to it and use that to get the course:
prof1 = Professor()
prof2 = Professor()
professor_list = [prof1, prof2]
class Professor:
def __init__(self):
self.name = ""
self.department = ""
self.course = ""
self.students = []
def teaches(self, student):
return student in self.students
class Student:
def __init__(self):
self.name = ""
self.activities = []
def get_course(self, professors):
for professor in professors:
if professor.teaches(self):
return professor.course
return None

Python3: Accessing func inside func inside class

I'm playing around and testing data structure and noticed you could print a list inside a class or a def function if you do class.list[0] or def.list[0], so I tried seeing how deep it could go and adding func inside func inside the class but instead of my expectation to just add more dots to the end of the value to chain them, it seems it doesn't work past 1 value.
class player:
def __init__(self, name, spec):
self.name = name
self.spec = spec
var1 = ('A1','A2')
def def1():
defA = "printed defA"
def def2():
defB = ('B1','B2')
print(player.def1.def2.defB[0]) #Doesn't work---
print(player.var1[0]) #Works fine---
In this case, would there be a way to print (or anything else) to the values nested deep in there? What would the address of this value be?

Resources