how to print object data with user input - python

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.

Related

Python: how to utilize instances of a class

New to OOP and python, I am struggling enormously to grasp what good classes actually are for. I tried to ask help from a lecturer who said "oh, then you should read about general methods to classes". Been putting in a days work but get no where.
I get it that a class allow you to collect an instance structure and methods to it, like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idA.show_list()
But what is even the point of a class if there were not MANY instances you would classify? If I have a method within the class, I must hard code the actual instance to call the class for. What if you want a user to search and select an instance, to then do operations to (e.g. print, compute or whatever)??
I thought of doing it like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idB = Items("idB", "B")
select_item = input("enter item id")
select_item.show_list()
Replacing hard coded variable with input variable doesn't work, probably logically. I then played with the idea of doing it like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
iL = [Items('idA', 'A'), Items('idB', 'B')]
selected_item = input("enter item id")
for selected_item in iL:
print(f'{selected_item.item_id} {selected_item.item_name}')
Now all are called thanks to making it a list instead of separate instances, but how do I actually apply code to filter and only use one instance in the list (dynamically, based on input)?
I would love the one who brought me sense to classes. You guys who work interactively with large data sets must do something what I today believe exist in another dimension.
See examples above^^
It seems you want to find all the instances of a certain element within a class.
This is as simple as:
print([x for x in iL if x.item_id == selected_item])
Now, you may ask why you can't just store the elements of iL as tuples instead of classes. The answer is, you can, but
("idA", "A")
is much less descriptive than:
item_id = "idA"
item_name = "A"
Any code you write with classes, you should in theory be able to write without classes. Classes are for the benefit of the coder, not the end-user of the program. They serve to make the program more readable, which I'm sure you'll find is a desirable property.
Your point here is to lookup for Items instances based on their item_id attribute.
That's a thing to create instances of a class.
It's a completely different thing to search for items objects stored in memory - that is not directly linked to the concept of OOP, classes and instances.
You could use dictionary to store references of your objects and then lookup in your dictionary.
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idB = Items("idB", "B")
lookup_dict = {"idA": idA, "idB": idB}
select_item = input("enter item id")
found_item = lookup_dict.get(select_item)
if found_item:
found_item.show_list()
else:
print(f"item {select_item} not found")

[Python]: How to update python property in a good way

I'm new to Python and I'm working on a crawler project.
I have a case want to ask you about good way to handle.
For example.
class Student:
def __init__(
self,
user_id: str,
name: str = None,
age: int = None,
gender: str = None
):
self.name = name
self.age = age
self.gender = gender
user_id = "test_user_id"
# after crawling data by selenium/scrapy
# we have 2 types to build/update class property
# STYLE 1:
student = Student(user_id)
student.name = "AAAA"
student.age = "18"
student.gender = "male"
# STYLE 2:
name = "AAAA"
age = "18"
gender = "male"
student = Student(
user_id=user_id,
name=name,
age=age,
gender=gender)
About the #STYLE 1, I'm not really it's a good way or not. But about #STYLE 2 I think it's gonna have some problem because we have to define a lot of variables (hard to debug), and we have to guarantee the variables have to be initialized before create class instance.
That's my question, please give me your guys idea about this or which way do you guy prefer.
I'm afraid this question will be closed soon as it requires opinion based answers, and is probably out of scope here. Nevertheless it raises an interesting point, so I will give my two cents.
If you are talking about properties that you will set at once, on creation or immediately after, I would definitely go with the second approach. As Punit said in a comment, you can (and usually will) directly pass the values, without creating intermediate variables unless they are already there. And if some of the properties are really necessary to work with the instance, I would avoid specifying a default value, thus making them required.
This way the instance creation is IMO both more readable and more reliable. And if you have really many arguments, you can require that most or all are passed as kwargs, which will further improve readability.
Then you may sometimes have other properties which are not needed, or may be even unknown, at creation time - and of course those will be set later, with the first style.
The best to go about this is to have all this code compressed into a smaller block. This helps make the code look more concise. Also, you forgot to set user_id in STYLE #1.
class Student:
def __init__(self, id: int, name: str, age: int, gender: str):
self.id = id
self.name = name
self.age = age
self.gender = gender
data = [] #scraped data from target site
# assuming a user instance looks like this: { name, age, id, gender }
# using list comprehensions to make it look cool
# you can replace the arguments in `Student()` with whatever fits the
# response from target site
users = [Student(i.id, i.name, i.age, i.gender) for i in data]
Hope this helps!
I would distinguish 2 cases here: Creation of the instance and update.
In the first case you can directly assign the values to the constructor of the class.
classStudent:
def __init__(self, user_id: str, name: str = None, age: int = None, gender: str = None):
self.user_id = user_id # You forgot this attribute!
self.name = name
self.age = age
self.gender = gender
student = Student(
# All the values you have available like you do in STYLE 2
)
In the case of updating it would be easier without using the variables and assigning them directly. Hard to debug, as you said.
student.name = "YYYY"
student.age = "18"
student.gender = "male"
There is nothing wrong in doing this in Python as you don't have to make getters and setters like other languages.
Even so, it would be recommended that you add conditionals to check if the values are valid before making the modification.

how assign list attributes to a class python 3 [closed]

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__().

How do i store multiple object attibutes to a single dictionary key?

I'm fairly new to the world of python and programming in general, and its rare that i get up the nerve to ask questions, but I'm stomped so i thought id suck it up and ask for help.
I'm making an Address book.
class Person():
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
contact = Person('Mike','1-800-foo-spam','email#email.com')
My question is how would go about storing all these attributes in a dictionary with contact.name as the key and contact.number and contact.email as the values.
Bonus question.
Should the dictionary be outside the class, perhaps in the main function?
or
Does it need to be a class variable(not completely sure how those work)
or an object variable
something like
self.storage = {}
Any help would be greatly appreciated.
Thank you!
If I put this information in a dictionary, I would do it like that:
class Person():
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
self.storage = {self.name: [self.number, self.email]}
def getStorage(self):
return self.storage
contact = Person('Mike','1-800-foo-spam','email#email.com')
print contact.storage
# or
print contact.getStorage()
But the whole idea of a dictionary is to have a number of keys and corresponding values. In this example, it always will be one only. So, another schema comes to my mind:
class Person():
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
# creating some example contacts
c1 = Person('Mike','1-800-foo-spam','email#email.com')
c2 = Person('Jim','1-700-foo-spam','e111mail#email.com')
c3 = Person('Kim','1-600-foo-spam','e222mail#email.com')
# creating a dictionary to fill it with c1..cn contacts
contacts = {}
# helper function to automate dictionary filling
def contactToDict(list_of_contacts):
for item in list_of_contacts:
contacts[item.name] = (item.number, item.email)
contactToDict([c1, c2, c3])
"""
expected output:
Mike: ('1-800-foo-spam', 'email#email.com')
Jim: ('1-700-foo-spam', 'e111mail#email.com')
Kim: ('1-600-foo-spam', 'e222mail#email.com')
"""
for key, val in contacts.items():
print str(key) + ": " + str(val)
The answer to the title of the question: a value should be a type of object with allows to have a "list" inside (i.e. list, tuple, another dictionary or custom type object having a number of attributes.)
You can pretty easily have a dictionary with tuples as the values.
a = {}
a["bob"] = ("1-800-whatever","bob#gmail.com")
If you wanted to make it a class variable, you'd just need to create an empty dictionary as part of the Person class:
class Person():
storage = {}
Then in __init__ you can store the new person's info in that dictionary:
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
Person.storage[name] = (number, email)
As you can see class attributes are accessed with the classname, but otherwise like any other attribute. You could store them as a tuple or a list if you need to update them. However if you intend to make changes, it might be better to store the actual Person object, to save having to update Person.storage and the actual person at the same time. This is even easier to do:
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
Person.storage[name] = self
self refers to the instance of Person that's being created with __init__. That's Mike in your example. Then you could access their values by attribute:
Person.storage["Mike"].number
Also as Kevin pointed out in a comment you might want to detect if the key already exists to avoid overwriting an old entry (eg. if there's already a Mike in the dictionary):
self.email = email
if name in Person.storage:
# Make unique name
Person.storage[name] = (number, email)

Searching a list to see if there is a match python

Basically this is within a class which appends objects of another class to list self. There are 200 objects in list self. So basically if I call self[1] I will get ['John',['Alex', 'Rob']. Basically 'john' refers to self.firstname and the other names refer to there group members. For example the below will print the firstnames and groupmembers of each object for all 200 objects
for line in self:
print line.firstname
for line in self:
print line.groupmembers
Now I have to create something that goes through all the names and checks the names. So basically if John has Alex and Rob as members then there has to be another object with a first name Alex and another object with a firstname Rob. So say there is no object with firstname Alex I want to print 'mismatch'. This is what I have so far but its not doing what its intended to do.
def name(self):
firstnames = []
for item in self:
firstnames.append(item.firstname)
for item1 in self:
for i in item1.groupmembers:
if i not in hello:
print 'mismatch'
Okay so first off, line and self are bad variable names.
self should only be used within a class to be used as a way to call or use its own variables.
Secondly, you say each value in this self list contains values like ['John',['Alex', 'Rob'], but then you go on to use it like a class object... and frankly that don't do make none sense.
So to remedy this, I'm going to assume its done with class objects. I would also rename self to something like school, and instead of calling an element of self; line, which yields no information to the reader.. call it a student!
I'm going to assume your class would start looking like this:
class Student:
# having an empty default value makes it easy to see what types variables should be!
firstname = ""
groupmembers = []
def __init__(self,firstname,groupmembers ):
self.firstname = firstname
self.groupmembers = groupmembers
Then if you have a list of people you can loop through them like so..
>>>school = [Student("foo", ["bar", "that guy"]),
Student("bar", ["foo", "that guy"])]
>>>for student in school:
print student.firstname
print student.groupmembers
foo
["bar", "that guy"]
bar
["foo", "that guy"]
Then to check it a students group members are in school you can add a function to the Student class
class Student:
# having an empty default value makes it easy to see what types variables should be!
firstname = ""
groupmembers = []
def __init__(self,firstname,groupmembers ):
self.firstname = firstname
self.groupmembers = groupmembers
def group_present(self, school):
# This is how you would get all the names of kids in school without list comprehension
attendance = []
for student in school:
attendance.append(student.firstname)
# this is with list comprehension
attendance = [ student.firstname for student in school]
#compare group members with attendance
#note that I write student_name, not student
## helps point out that it is a string not a class
for student_name in self.groupmembers:
if not student_name in attendance:
print "Group member '{}' is missing :o!! GASP!".format(student_name)
In idle:
>>> school[0].group_present(school)
Group member 'that guy' is missing :o!! GASP!
Hope that helps!
I am not sure if i understand exactly but maybe you can use contains
self[1].__contains__('Alex')
this should return true in case of existence or false otherwise.

Categories

Resources