I am a newbie to Python. I need to create a simple student class which includes first name, last name, id, and a dictionary which maps course name to its grade.
class Student:
def __init__(self, firstName, lastName, id, _____ (dictionary values)):
self._firstName = firstName;
self._lastName = lastName;
self._id = id;
self.
My question is how can I initizalize the dictionary values inside the constructor?
For example, let`s say I would like to add 3 course to grade mappings:
"math: 100"
"bio: 90"
"history: 80"
For example:
student1 = Student("Edward", "Gates", "0456789", math: 100, bio: 90, history: 80)
The last 3 values should go into the dictionary.
Since the number of key-value which can be part of the dictionary can vary, what should I write in the constructor parameter signature?
I want to send all the student values when I call the constructor...
If you are looking to add a dictionary Mathias' answer suffices with the key word arguments in python.
However, if you wish to add object variables from the key word arguments, you require setattr
For example, if you want something like this:
student1 = Student("Edward", "Gates", "0456789", {'math': 100, 'bio': 90, 'history': 80})
print student1.math #prints 100
print student1.bio #prints 90
Then this will do the trick:
class Student(object):
def __init__(self, first_name, last_name, id, **kwargs):
self.first_name = first_name
self.last_name = last_name
self.id = id
for key, value in kwargs.iteritems():
setattr(self, key, value)
student1 = Student("Edward", "Gates", "0456789", {'math': 100, 'bio': 90, 'history': 80})
Note that **kwargs will unpack only something like dictionary or tuple of tuples. If you wish to send a list of values without keys, you should use *args. Check here to know more.
Python collects all keyword arguments for you.
class Student:
def __init__(self, firstName, lastName, id, **kwargs):
self._firstName = firstName;
self._lastName = lastName;
self._id = id;
self. _grades = kwargs
Here is an excellent explanation about kwargs in python
Why not send the complete grades dictionary to the your class and store it in a variable.
(Also please note that in Python there is no semicolon at the end of the line)
class Student:
def __init__(self, firstName, lastName, id, grade_dict):
self._firstName = firstName
self._lastName = lastName
self._id = id
self._grades = grade_dict
def get_grades(self):
return self._grades
and then when you want to initialize and use the grades:
student1 = Student("Edward", "Gates", "0456789", {'math': 100, 'bio': 90, 'history': 80})
grades = student1.get_grades()
for key, value in grades.items():
print 'Marks in {}: {}'.format(key, str(value))
Which prints:
Marks in bio: 90
Marks in math: 100
Marks in history: 80
You can try something like:
student = Student("Edward", "Gates", "0456789", {"math": 100, "bio": 90, "history": 80})
And inside your constructor you can copy these values to a new dictionary:
class Student:
def __init__(self, firstName, lastName, id, grades):
self._firstName = firstName;
self._lastName = lastName;
self._id = id;
self._grades = grades.copy()
Notice that we're copying the dictionary to a new attribute because we want to avoid keeping a reference.
First, make sure to remove the semicolon ; from your code - it won't compile!
Second, I believe you're looking to do something like:
class Student:
def __init__(self, first_name, last_name, _id, **courses):
self._first_name = first_name
self._last_name = last_name
self._id = _id
self.courses = courses
def print_student(self):
print self._first_name
print self._last_name
print self._id
for key in self.courses:
print key, self.courses[key]
courses = {'math': 100, 'bio': 90, 'history': 80}
s = Student("John", "Smith", 5, **courses)
s.print_student()
OUTPUT
John
Smith
5
bio 90
math 100
history 80
Related
I am sorry if this was answered before, but I could not find any answer for this problem at all.
Let's say I have this class and list of objects:
def Person:
def __init__(self, name, country, age):
self.name = name
self.country = country
self.age = age
persons = [Person('Tom', 'USA', 20), Person('Matt', 'UK', 19), Person('Matt', 'USA', 20)]
Now I would like the user to search for a person by entering any combination of attribute values and I want to return the objects that have all these values exclusively. For example, if the user enters: 'Matt', 'USA' and no age, I want the program to return the third person only who's Matt and is from the USA and not return all three objects because all of them have some of the entered combination of attribute values.
My implementation currently uses an if statement with the or operator which would return all the objects since the usage of or would return all the objects if one statement is True, which is what I am trying to solve.
Thanks in advance.
You can use a list comprehension for the task. And the if condition should check if the value is None else check in the list.
class Person:
def __init__(self, name, country, age):
self.name = name
self.country = country
self.age = age
def __repr__(self):
return "[{},{},{}]".format(name, country, str(age))
persons = [Person('Tom', 'USA', 20), Person('Matt', 'UK', 19), Person('Matt', 'USA', 20)]
name = "Matt"
country = "USA"
age = None
result = [
p for p in persons
if (name == None or p.name == name) and
(country == None or p.country == country) and
(age == None or p.age == age)
]
print(result) #[[Matt,USA,None]]
I have a class with a constructor that receives several arguments. These arguments I get from an external file, which is a list of dictionaries.
My problem is that some dictionaries have missing fields. If a field is missing, I want the constructor to simply receive None instead. But as the code is written now, it exits on an exception.
This is a simple illustration of the situation
class Person()
def __init__(self, id, age, name, gender):
self.id = id
self.age = age
self.name = name
self.gender = gender
people_list = pickle.load(open("some_file.p", "rb"))
first_person = people_list[0] # this is a dictionary {'id': '1234', 'age': 27, 'name': 'robert'}
Person(first_person['id'], first_person['age'], first_person['name'], first_person['gender'])
As the code is written right now, I get an exception that 'gender' does not exist as a key in the dictionary, which is true. I want any missing field to gets passed a None value, but without doing a billion ifs or try .. excepts. Is there a good way to do this? Obviously without still incurring an exception.
In general, you can get a value from a dict with a default if it doesn't exist with:
d = {'a': 1}
print(d.get('b')) # prints None
But in your case, this would be more appropriate:
class Person():
# the defaults are defined in the constructor
def __init__(self, id, age=None, name=None, gender=None):
self.id = id
self.age = age
self.name = name
self.gender = gender
people_list = pickle.load(open("some_file.p", "rb"))
for person in people_list:
Person(**person) # assuming they at least all have an 'id'
Of course, this only works if the keys of the dictionaries match the names of the parameters exactly.
The ** operator 'unpacks' the dictionary, so this:
d = {'a': 1, 'b': 2}
f(**d)
Is the same as:
f(a=1, b=2)
I have a parent class and two child class. I can create one object from any class my program run without Error. But when use add_emp method of Manager class, objects added to emp list but when use print_emp method objects that was add to list not return!!!!
class Emplyee:
increaspay = 1.09
def __init__(self, fname, lname, email,pay):
self.fname = fname
self.lname = lname
self.email = email
self.pay = pay
def Fullname(self):
print(f'{self.fname} {self.lname}')
def Applypay(self):
print(f'NewPay = {int(self.pay*Emplyee.increaspay)}')
class Developer(Emplyee):
def __init__(self, fname, lname, email, pay, lang):
super().__init__(fname, lname, email, pay)
self.lang = lang
class Manager(Emplyee):
def __init__(self, fname, lname, email, pay, emps=None):
super().__init__(fname, lname, email, pay)
if emps is None:
self.emps = []
else:
self.emps = emps
def add_emp(self, emp):
if emp not in self.emps:
self.emps.append(emp)
def remove_emp(self, emp):
if emp in self.emps:
self.emps.remove(emp)
def print_emp(self):
for emp in self.emps:
return (emp.Fullname())
Try return [emp.Fullname() for emp in self.emps].
In print_emp(self): clause of your code, python loops over self.emps. That is, it first sets emps to be the first item of self.emps. So emp.Fullname() initially is the name of the first employee. Now when python sees return, it returns this emp.Fullname(), and just finishes the method. This is why your code returns only the name of the first employee.
I have two classes
Club with property id and name
Student with property id, name and clubs (list)
One student can be part of multiple clubs.
One club can have multiple students
class Club:
def __init__(self, id, name):
self.id = id
self.name = name
class Student:
def __init__(self, id, name, clubs):
self.id = id
self.name = name
self.clubs = clubs
I want to have a dictionary where the key is club name and value is list of students.
I have around 30 different many to many relationships in the application.
Is there a way to do it in a generic way?
A crude inverter could be like below.
def reverse(elems, array_name, i_key):
dic = {}
for elem in elems:
for elem_field in elem[array_name]:
key = elem_field[i_key]
if key not in dic:
dic[key] = []
dic[key].append(elem)
return dic
club_a = { 'name': 'a'}
club_b = { 'name': 'b'}
club_c = { 'name': 'c'}
stud_a = { 'id': 1, 'clubs': [club_a, club_b]}
stud_b = { 'id': 2, 'clubs': [club_b, club_c]}
print(reverse([stud_a, stud_b], 'clubs', 'name'))
# a: stud_a
# b: stud_a, stud_b
# c: stud_b
I am running into the following problem:
class Student():
def __init__(self,firstname, lastname, **kwargs):
self.firstname = firstname
self.lastname = lastname
student1 = Student("John" ,"Johnson" , {"Nationality": "Middle-Earth" , "Sports": ["volleyball","skiing"]})
I want to be able to create students that all have a first and a last name, but only some have information about nationality or sports. (Actually I am experimenting with reconstructing objects from json files.)
So I want to turn kwarg key into instance variable names, like this pseudo-code
for key,value in kwargs:
self.key = value
the above is pseude-code, but is there a way to do this in correct python? in other words: derive instance variable names from kwargs rather than all predefined.
I know this won't result in errorproof code etc..., but I want to know if it can be done.
You can use this in the __init__ method:
for k, v in kwargs.items():
setattr(self, k, v)
However, this is not recommended for code than needs to be reusable. If there are typos in the keyword parameters, you won't catch them. Code-checking tools such as pylint will not recognize class attributes initialized like that. You can use the following pattern (especially if there are many kewyord arguments):
class Student:
def __init__(self, firstname, lastname, **kwargs):
self.firstname = str(firstname)
self.lastname = str(lastname)
self.nationality = None
self.sports = None
for k, v in kwargs.items():
if k in self.__dict__:
setattr(self, k, v)
else:
raise KeyError(k)
# this works
s=Student('John', 'Doe', sports=['socker'])
# this will give an error
s=Student('John', 'Doe', sprots=['socker'])
You need to pass unpacked kwargs to Student and use setattr(object, name, value) to set the values:
class Student():
def __init__(self,firstname, lastname, **kwargs):
self.firstname = firstname
self.lastname = lastname
for (k,v) in kwargs.items():
setattr(self, k, v)
student1 = Student("John" ,"Johnson" , **{"Nationality": "Middle-Earth" , "Sports": ["volleyball","skiing"]})
print(student1.__dict__)
Output:
{'lastname': 'Johnson', 'Sports': ['volleyball', 'skiing'], 'firstname': 'John', 'Nationality': 'Middle-Earth'}
I recommend stating up front what attributes an instance can have, and using sentinel values like None to indicate the lack of a "real" value over eliminating the attribute altogether. For example:
class Student():
def __init__(self,firstname, lastname, nationality=None, sports=None):
self.firstname = firstname
self.lastname = lastname
self.nationality = nationality
self.sports = [] if sports is None else sports
Then
student1 = Student("John" ,"Johnson" , "Middle-Earth" , ["volleyball","skiing"])
student2 = Student("Bob", "Smith", nationality="Australia") # No sports
student3 = Student("Alice", "Doe", sports=["hockey"]) # No nationality
If you want to parse JSON which may have key names that don't match your parameter names, define a class method to do the processing to get appropriate arguments. For example,
#classmethod
def from_dict(cls, data):
firstname = data["FirstName"]
lastname = data["some last name"]
nationality = data.get("Nationality")
sports = data.get("Sports", [])
return cls(firstname, lastname, nationality, sports)
Then
student = Student.from_dict({'FirstName': 'John', 'some_last_name': 'Doe',})