I’m new and still learning but I’m making a random character Generator and I don’t know how to make it stop or end the code and start a new one.
import random
Rac = ["Human", "Half-Human", "Not Human"]
Race = random.choice(Rac)
Age = random.randint(1,100)
skil = [“Beserker”,”Mage”,”Assassin”]
Skill = random.choice(skil)
Gende = [“Male”,”Female”]
Gender = random.choice(Gende)
class human:
def __dir__(self):
return[Race,Age,Skill,Gender]
person = human()
print(dir(person))
print(“Race: {}, Age: {}, Class: {}, Gender: {}”.format(Race,Age,Class,Gender))
I have two of these but the ages keep printing out the same and I don’t know how to separate them so it’s a different age and not the same number for both.
I need to end the Age for that generator because it interferes and makes it all the same age, Instead of random ages.
Sorry for being confusing.
Based on what I understood,
First of all, I have corrected the code and removed syntax errors.
(Below given code is not an answer. It is just the updated code. I have given my answer below that.)
import random
Rac = ["Human", "Half-Human", "Not Human"]
Race = random.choice(Rac)
Age = random.randint(1,100)
skil = ["Beserker", "Mage", "Assassin"]
Skill = random.choice(skil)
Gende = ["Male", "Female"]
Gender = random.choice(Gende)
class human:
def __dir__(self):
return [Race, Age, Skill, Gender]
person = human()
print(dir(person))
print("Race: {}, Age: {}, Skill: {}, Gender: {}".format(Race, Age, Skill, Gender))
My answer :
Now,
When you create the random object,
Here : Age = random.randint(1,100)
It gets called only once, so only one random number is generated and you are using it 2 times.
I have two of these but the ages keep printing out the same and I don’t know how to separate them how do I separate them so it’s a different age and not the same number for both
What you need, is to generate this number inside the class definition. So it will get called every time you create the object of that class.
Code:
import random
class human:
def __dir__(self) -> list:
self.Rac = ["Human", "Half-Human", "Not Human"]
self.Race = random.choice(self.Rac)
self.Age = random.randint(1,100)
self.skil = ["Beserker", "Mage", "Assassin"]
self.Skill = random.choice(self.skil)
self.Gende = ["Male", "Female"]
self.Gender = random.choice(self.Gende)
return [self.Race, str(self.Age), self.Skill, self.Gender]
person = human()
print(dir(person))
(Note the str() conversion of self.Age)
Now some other knowledge:
dir() method calls __dir__ method in the class and __dir__ is supposed to return list containing items of similar data types (int or str).
This means list should contain all integers or all strings.
For example, code:
class Hello():
def __dir__(self):
return ["1", "2", "3"]
print(dir(Hello()))
Output: ['1', '2', '3']
if:
class Hello():
def __dir__(self):
return [1, "2", 3]
print(dir(Hello()))
Output: TypeError: '<' not supported between instances of 'str' and 'int'
For more information: What's the difference between dir() and __dir__?
Related
I develop bottom up, starting with small simple methods to go to the big full fledged implementation
class Pop(object):
def welcome(self, name, new_member = False):
response = ""
if new_member:
response = " NOT"
return str("hello there "+name+", you seem"+response+" to be a member\n")
def ageVerification(self, name, age, new_member = False):
the_welcome_string = self.welcome(name, new_member)
minimum = ""
excuse = ""
if age < 16:
minimum = " NOT"
excuse = ", sorry"
return str(the_welcome_string+str(age)+" is"+minimum+" the minimum required age to buy beer in Belgium"+excuse+"\n")
def theWholething(self, name, age, address, new_member = False):
if age < 16:
appology = str("you cannot order any beer\n")
else:
appology = str("your beer will be shipped to "+address+"\n")
return str(self.ageVerification(name, age, new_member)+appology)
# EOF
My question is if it is normal that when i reach theWholeThingMethod, I carry along all the parameters of the previously defined methods? Is this pythonic?
My population class has almost 20 "helper" methods called in theWholeThing, and it seems I am just fiddling with parameters to get them in the right order ...
theWholeThing(self,\
name,\
age,\
address,\
registered = True,\
first_date_entered,\
last_date_entered,\
purchased_amount,\
favorite_beer,\
promotional_code,\
and_so_on0,\
and_so_on1,\
and_so_on2,\
and_so_on3,\
and_so_on4,\
and_so_on5,\
and_so_on6,\
and_so_on7,\
and_so_on8,\
and_so_on9,\
and_so_on10):
My question is if it is normal that when i reach theWholeThingMethod, I carry along all the parameters of the previously defined methods? Is this pythonic?
Neither.
There is really no point in having a class if all the methods take all the arguments anyway. These might as well just be functions.
There are many ways this could be done, depending on whether the various parameters are mandatory, or what happens when one is not provided, but here is one possibility:
from dataclasses import dataclass
#dataclass
class Pop(object):
name: str
age: int
address: str
new_member : bool = False
def welcome(self):
response = ""
if self.new_member:
response = " NOT"
return str("hello there "+self.name+", you seem"+response+" to be a member\n")
def ageVerification(self):
the_welcome_string = self.welcome()
minimum = ""
excuse = ""
if self.age < 16:
minimum = " NOT"
excuse = ", sorry"
return str(the_welcome_string+str(self.age)+" is"+minimum+" the minimum required age to buy beer in Belgium"+excuse+"\n")
def theWholething(self):
if self.age < 16:
appology = str("you cannot order any beer\n")
else:
appology = str("your beer will be shipped to "+self.address+"\n")
return str(self.ageVerification()+appology)
# EOF
Note: #nneonneo had a great suggestion of using a dataclasses, so answer tweaked to incorporate that
userInput = input("Enter Name: ")
class person:
def __init__(self, name, age, job):
self.name = name
self.age = age
self.job = job
People = [
person('Josh',23,'Consultant'),
person('Maya',25,'Accountant'),
person('Dan',32,'Social Worker'),
person('Keon',38,'Biomaterials Developer'),
person('Michelle',28,'Surgeon'),
person('Joey',34,'Lawyer')
]
so if userInput = Josh, it would print Josh's name, age, and job
The slow method is to iterate over the list and find a match.
def find_person(people, name):
for person in people:
if person.name == name:
return person
raise ValueError("No matching person found")
This is O(n) in the size of the list, which will cause problems if your list of people is large.
But since you know in advance that you're going to be looking up people by name, you can use the person's name as a dictionary key, effectively indexing by the name rather than an integer value. So rather than creating a list of people, creating a dictionary
people = {
'Josh': person('Josh',23,'Consultant'),
'Maya': person('Maya',25,'Accountant'),
'Dan': person('Dan',32,'Social Worker'),
'Keon': person('Keon',38,'Biomaterials Developer'),
'Michelle': person('Michelle',28,'Surgeon'),
'Joey': person('Joey',34,'Lawyer'),
}
Then "look up a person by name" is as simple as people[name]. Of course, you'll want to hide this complexity behind a class or something and make the client-facing side look like a list, or whatever data structure you want it to look like. This approach also currently assumes that no two people will ever have the same first name, though you can work around that by having a dictionary of lists if there's a possibility of duplicates.
I am making a text based adventure game in python. Once the game begins, I would like to create an instance of a class called "Character" which is the player's character object. I would like the user to be able to choose the race of the character they want to play. So far I have:
class Race:
def __init__(self, name, passive, hp):
self.name = name
self.passive = passive
self.hp = hp
and
class Lizard(Race):
def __init__(self, name, passive, hp):
super().__init__(name, passive, hp)
self.name = 'Lizardman'
self.passive = 'Regrowth'
self.hp = 20
def regrowth(self):
if 0 < self.hp <= 18:
self.hp += 2
and
def race_select():
races = ['Lizard']
while True:
for i, j in enumerate(races):
print(f"[{i + 1}]", j)
choice = int(input('Pick a race:'))
if choice <= len(races):
print('You are a ', races[choice - 1])
return races[choice - 1]
else:
continue
If I understand correctly, if I wanted the race to be a Lizard, I would still have to do
character = Lizard('Lizardman', 'Regrowth', 20)
Is there an easy way to let the user choose the race and the object to be created accordingly? Thanks
A simple solution would be to map a name to a class using a dictionary. As a simple example:
race_map = {"lizard": Lizard,
"human": Human} # I'm adding a theoretical other class as an example
choice = input('Pick a race:')
race_initializer = race_map.get(choice, None) # Get the chosen class, or None if input is bad
if race_initializer is None:
# They entered bad input that doesn't correspond to a race
else:
new_creature = race_initializer(their_name, their_passive, their_hp)
new_creature is now the new object of the chosen class.
You may want to standardize the input using choice.lower() to ensure that capitalization doesn't matter when they enter their choice.
I changed it to allow for specifying a race by a string name instead of a number. If you wanted a number, you could keep your list, but apply the same idea. Something like:
race_list = races = [('Lizard', Lizard), ('human', Human)]
choice = int(input('Pick a race:'))
try:
race_initializer = race_list[choice][1] # 1 because the class object is the second in the tuple
new_creature = race_initializer(their_name, their_passive, their_hp)
except IndexError:
# Bad input
I included the name in the race_list so that you can loop over the list and print out index->name associations for the user to pick from.
You may also want to use a more robust structure than a plain tuple to store name->initializer mappings, but it works well in simple cases.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I need to create a class student and then assign him or her a subject (maths, science, etc.) and then the grade by subject.
Basically, I have created a class student with name, gender,etc. Then I need to add more than one subject.
But i dont understand how one student object can get more than one subject and probably a greade per subject.
class student:
def __init__(self,name,age,gender,subject):
self.name = name
self.age = age
self.gender = gender
self.subject = subject
def __str__(self):
return ('{},{},{},{}'.format(self.name,self.age,self.gender,self.subject))
new = student('Alan',17,'M','Science')
Please if someone can help me to clarify a little bit I appreciate.
thanks
From your question, I gather that you have already worked with entity relations (ERDs), which is why you are thinking in terms of associations -- which is good. I'm assuming this is homework, so I don't want to give away too much. However, the code below should get you started.
from typing import List, Dict
class CollegeClass:
def __init__(self, class_code: str, name: str):
self.class_code = class_code #type: str
self.name = name
def __str__(self):
return f"{self.class_code}, {self.name}"
def __repr__(self):
return str(self)
class Student:
def __init__(self):
self.current_classes = dict() # type: Dict[str, CollegeClass]
def enroll(self, college_class: CollegeClass):
if college_class.class_code in self.current_classes:
print("The student is already taking the class.")
return
self.current_classes[college_class.class_code] = college_class
if __name__ == '__main__':
math = CollegeClass("mth101", "Intro to Math")
english = CollegeClass("eng201", "Intro to Fiction")
eric_praline = Student()
eric_praline.enroll(math)
eric_praline.enroll(english)
for _, cls in eric_praline.current_classes.items():
print(cls)
There are many ways to accomplish this task. One solution is to not specify the subject when creating the student. Instead, you would create the student object and then add subjects to it.
For example:
student = Student(name="John Smith")
for subject_name in ("Math", "Science", "Literature"):
student.add_subject(subject_name)
That gives you a new student who has three subjects. The add_subject method might look something like this:
class Student(object):
def __init__(self, name, age, gender):
...
self.subjects = {}
...
def add_subject(self, name):
self.subjects[name] = Subject(name)
To assign grades you would do something like this, perhaps
student.add_grade("Math", "A")
student.add_grade("Science", "B")
student.add_grade("Literature", "C")
add_grade would then take the grade name, look up the subject object from self.subjects, and call a method on that subject object to add the grade.
For example:
def add_grade(self, subject_name, grade):
subject = self.subjects[subject_name]
subject.add_grade(grade)
Your class Subject could be something very simple:
class Subject(self):
def __init__(self, name):
self.name = name
self.grade = None
def add_grade(self, grade):
self.grade = grade
Note: the above assumes you want a single grade per subject. If you want multiple grades, you can change self.grade to be self.grades and have it be a list.
Class Student represents just a type of people
Object of class Student represents a particular student, e.g. John Smith
Class Subject represents something students can learn in general
Object of class Subject represents a particular class students can take, e.g. Math 2017
Grade does not belong in either of these, because it only makes sense with a combination of both. So I would suggest creating some data storage, e.g. a list of tuples to store a grade for each combination of student/subject objects you want to keep track of, e.g.
Grades = [
(john_smith, math_2017, 'A+'),
...
]
class Subject(object):
def __init__(self, name, grade=None):
self.name = name
self.grade = grade
class student:
def __init__(self,name,age,gender, subjects=[]):
self.name = name
self.age = age
self.gender = gender
self.subjects = {}
for sub in subjects:
self.subjects[sub] = Subject(sub)
# Create new student with 2 subjects (Art and Science)
new = student('Alan',17,'M', subjects=['Art', 'Science'])
# You can wrap the following processes in functions if so desired
# Add a new subject later on (Math)
new.subjects['Math'] = Subject('Math')
# Add grades
new.subjects['Art'].grade = 'C'
new.subjects['Science'].grade = 'A+'
new.subjects['Math'].grade = 'B-'
# Get a list of subjects and grades
print([(sub.name, sub.grade) for _, sub in new.subjects.items()])
>>>[('Art', 'C'), ('Science', 'A+'), ('Math', 'B-')]
But i [don't] understand how one student object can get more than one subject and probably a [grade] per subject.
Pass in a dictionary of {subject: grade} pairs.
Code
class Student:
def __init__(self, name, age, gender, subjects=None):
self.name = name
self.age = age
self.gender = gender
# Handle mutable keyword defaults
if subjects is None:
self.subjects = {}
else:
self.subjects = subjects
def __repr__(self):
return ("{0.name}, {0.age}, {0.gender}, {0.subjects}".format(self))
subjects = {"Math": "A", "Biology": "B-", "Chemistry": "A"}
s = Student("Joe", 20, "M", subjects=subjects)
s
# Joe, 20, M, {'Math': 'A', 'Chemistry': 'A', 'Biology': 'B-'}
s.subjects["Math"]
# 'A'
Assigning None to a keyword argument is a convention for avoiding a well-known gotcha when assigning mutable arguments, e.g. lists, dictionaries. The lines that handle subjects is equivalent to this one-liner:
self.subjects = {} if subjects is None else subjects
The __repr__() method was defined, which you may wish to include along with __str__().
Am new to Python OOP. Please dont be harsh. Here is my code which calculates which is the fastest time of an athlete from a list and displays them. But When Running, I get this error:
z= add.mylist.min()
NameError: global name 'add' is not defined
My Code:
class Athlete:
def add(self):
list=[]
mylist=[]
for i in range(2):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time: ")
list.append(self.name)
mylist.append(self.fastest_time)
print "Names: ",list
print "Fastest times: ",mylist
def display(self):
z= add.mylist.min()
w= add.mylist.index(z)
print "Minimum time: ",z
print "Name of athelte with fastest time: ",list[w]
x = Athlete()
x.add()
x.display()
You need to refer to methods on the instance with the self parameter. In addition, your add() method needs to return the mylist variable it generates, you cannot refer to method local variables as attributes on methods:
def display(self):
mylist = self.add()
z = min(mylist)
w = mylist.index(z)
def add(self):
list=[]
mylist=[]
for i in range(2):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time: ")
list.append(self.name)
mylist.append(self.fastest_time)
print "Names: ",list
print "Fastest times: ",mylist
return mylist
That is what self is for, as a reference point to find instance attributes and other methods on the same object.
You may want to rename list to something that does not shadow the built-in type.
Martijn has already answered your question, so here are some remarks and code style tips:
New-style classes derive from object
You have both athlete names and their times, those belong together as key-value pairs in a dictionary instead of two separate lists
Don't use print statements inside class methods, a class method should return an object that you then can print
what if you have more then 2 athletes for which you want to enter the time? If you make the number of athletes an argument of your function, you can add a variable number of athlethes
give descriptive variable names (not mylist) and don't use names of builtin functions (like list) as variable name
variables that you want to use throughout your class can be initalized in an __init__method.
For printing, use the format function instead of using commas
use if __name__ == '__main__' so that your Python file can act as either reusable modules or as standalone program
Taking these into account, I would rewrite your code to something like this:
from collections import defaultdict
class Athlete(object): # see (1)
def __init__(self): # see (6)
self.athlete_times = defaultdict(str) # see (2)
def add_athletes_and_times(self, n): # see (4)
for i in range(n):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time (in seconds): ")
self.athlete_times[self.fastest_time] = self.name
def get_fastest_time(self):
return min(self.athlete_times) # see (3)
if __name__ == '__main__': # see (8)
x = Athlete()
x.add_athletes_and_times(2)
for fast_time in x.athlete_times:
print "The fastest time of athlete {0} is {1} seconds.".format(
x.athlete_times[fast_time], fast_time) # see (7)
fastest_time = x.get_fastest_time()
print "The overall fastest time is: {0} seconds for athlete {1}.".format(
fastest_time, x.athlete_times[fastest_time])