AttributeError Problem with Multiple inheritance in python - python-3.x

I wanted to calculate the Total and Average Marks of a student with multiple inheritances in python. But whenever I create an object for my child class it gives me access to all the methods of parent classes but shows an AttributeError when I call the method of the child class. I tried to use the super() function but the result is the same.
I just paste my code below. Can you suggest to me a solution to that?
class Student_Marks:
def __init__(self):
# initializing variables
self.__roll: int
self.__marks1: int
self.__marks2: int
def getMarks(self):
self.__roll = int(input("Enter Roll No: "))
self.__marks1, self.__marks2 = map(int, input("Enter Marks: ").split())
return self.__roll, self.__marks1, self.__marks2
class Cocurricular_Marks:
def __init__(self):
self.__activemarks: int
def getActiveMarks(self):
self.__activemarks = int(input("Enter Co Curricular Activities Marks: "))
return self.__activemarks
class Result(Student_Marks, Cocurricular_Marks):
def __init__(self):
super().getMarks()
super().getActiveMarks()
def display(self):
total = self.__marks1 + self.__marks2 + self.__activemarks
avg = total / 3
print("Roll No: ", self.__roll)
print("Total Marks: ", total)
print("Average Marks: ", avg )
# creating Objects
res = Result()
res.getMarks()
res.getActiveMarks()
res.display() # I got problem here

You're prepending the attributes with two underscores in the classes, this mangles the name of the attribute (see the documentation on Private Variables).
For instance, Student_Marks's __roll will be mangled to _Student_Marks__roll as you exit getMarks.
Hence Result.display() not being able to access self.__marks1, but it can access it as self._Student_Marks__marks1.
See the following minimal example.
class K:
__a = 1
class KK(K):
pass
k = K()
k.__a # AttributeError: 'K' object has no attribute '__a'
k._K__a # 1
kk = KK()
kk._K__a # 1

Related

Why am I getting this error? AttributeError: type object 'bubbleSort' has no attribute 'array'

I'm trying to make my own bubble-sort algorithm for learning purposes. I'm doing it by:
Making a random array
Checking if the first two indexes of the array need to be swapped
it does this throughout the whole list
and does it over and over until when looping through until the end it doesn't need to swap anything anymore then the loop breaks
but when I print any variable in the class it says that the class has no attribute of the variable.
this is my code right now
from random import randint
class bubbleSort:
def __init__(self, size):
self.size = size # Array size
self.array = [] # Random array
self.sorted = self.array # Sorted array
self.random = 0 # Random number
self.count = 0
self.done = False
self.equal = 0
while self.count != self.size:
random = randint(1, self.size)
if random in self.array:
pass
else:
self.array.append(random)
self.count += 1
def sort(self):
while self.done != True:
self.equal = False
for i in range(self.size):
if i == self.size:
pass
else:
if self.sorted[i] > [self.tmp]:
self.equal += 1
if self.equal == self.size:
self.done = True
else:
self.sorted[i], self.sorted[i + 1] = self.sorted[i+1], self.sorted[i]
new = bubbleSort(10)
print(bubbleSort.array)
This is what outputs
Traceback (most recent call last):
File "/home/musab/Documents/Sorting Algorithms/Bubble sort.py", line 38, in <module>
print(bubbleSort.array)
AttributeError: type object 'bubbleSort' has no attribute 'array'
In your case, you have a class called bubbleSort and an instance of this class called new, which you create using new = bubbleSort(10).
Since bubbleSort only refers to the class itself, it has no knowledge of member fields of any particular instance (the fields you create using self.xyz = abc inside of the class functions. And this is good, imagine having two instances
b1 = bubbleSort(10)
b2 = bubbleSort(20)
and you want to access the array of b1, you need to specify this somehow. The way to do it is to call b1.array.
Therefore, in your case you need to print(new.array).
bubbleSort is a class type, each object of this class type has its own array. To access array, one must do it through a class object. __init__ is called when creating a class object.
give the following a try:
bubbleSortObj = bubbleSort(10) # create a bubbleSort object
print(bubbleSortObj.array) # print the array before sort
bubbleSortObj.sort() # sort the array
print(bubbleSortObj.array) # print the array after sort
Notes
In __init__ you've got:
self.array = [] # Random array
self.sorted = self.array # Sorted array
In this case, array and sorted point to the same list and changing one would change the other. To make a copy of a list, one approach (among many) is to call sorted = list(array)
If there are any local function variables you can remove the self, eg, self.count = 0 can just be count = 0, as it's not needed again once it's used, and doesn't need to be a class member

Write class such that calling instance returns all instance variables

I have answered my own question - see answer below
I'm writing a class, and I want this behavior:
a = f(10,20)
some_funct(a.row) # some_function is given 10
some_funct(a.col) # some_function is given 20
some_funct(a) # some_function is given a tuple of 10, 20 <-- THIS ONE :)
The last behavior is stumping me. I have not seen any examples that cover this.
Thus far:
class f(object):
"""Simple 2d object"""
row: int
col: int
def __init__(self, row, col):
self.row = row
self.col = col
Explictly I do not want another method, say, self.both = row, col.
I just want to 'call' the instance
I'm new to classes, so any improvements are welcome. Properties, setters, getters etc.
EDIT 1:
Replaced "print" with "some_function" in the question, and modified title
You can do like this
class f(object):
"""Simple 2d object"""
row: int
col: int
def __init__(self, row, col):
self.row = row
self.col = col
def __str__(self):
return f"row = {row}, col = {col}"
and print like this
a = f(10,20)
print(a) # row = 10, col = 20
This might help
class f(object):
"""Simple 2d object"""
row: int
col: int
def __init__(self, row, col):
self.row = row
self.col = col
def some_funct(self):
return (self.row, self.col)
You can access like
a = f(10,20)
a.some_funct() # (10, 20)
# or
row, col = a.some_funct()
From python 3.7 dataclasses have been introduced and their goal is to create classes that mainly contains data. Dataclasses comes with some helper function that extract the class attributes dict/tuples. e.g.
from dataclasses import dataclass,asdict,astuple
#dataclass
class f:
x: int
y: int
f_instance = f(10,20)
asdict(f_instance) # --> {'x': 10, 'y': 20}
astuple(f_instance) # -> (10,20)
EDIT I : Another technique would be to use namedtuple e.g.:
from collections import namedtuple
f = namedtuple('p',['row','col'])
a =f(10,20)
a.row #-> 10
a.col #-> 20
class f(tuple):
"""Simple 2d object"""
def __new__(cls, x, y):
return tuple.__new__(f, (x, y))
def __init__(self, x, y):
self.col = x
self.row = y
foo = f(1,2)
print(foo.col)
>>>1
print(foo.row)
>>>2
print(foo)
>>>(1, 2)
Importantly:
If you want it to behave like a tuple then make it a subclass of tuple.
Much stuffing around but stumbled upon an external site which gave me clues about the keywords to search on here. The SO question is here but I have modified that answer slightly.
I'm still a little confused because the other site says to use new in the init as well but does not give a clear example.

Problem retrieving individual objects in pickled dictionary (Python 3)

My program stores "food" objects that are pickled into a dictionary and stored in a csv file, which acts as a database. I want to retrieve individual food objects on command from the dictionary, but when I attempt to I seem to only retrieve the last object in the dictionary.
import pickle
class Food(object):
fooddict = dict({})
def __init__(self, name, weight, calories, time):
self.name = name
self.weight = weight
self.calories = calories
self.time = time
def __str__(self):
return '{self.name}s'.format(self=self) + \
' weigh {self.weight}'.format(self=self) + \
' ounces, contain {self.calories}'.format(self=self) + \
' calories, and stay fresh for {self.time}'.format(self=self) + \
' days.'
#classmethod
def createFoodInput(cls):
name = str(input("Enter the name: "))
weight = float(input("Enter the weight: "))
calories = float(input("Enter the calories: "))
time = float(input("Enter how many days it can store for: "))
return cls(name, weight, calories, time)
def storeFoodDict(f):
fooddict = Food.retreiveFoodDict()
if fooddict == "Empty File":
fooddict = dict({f.name: f})
with open("food.csv", 'wb') as filewriter:
try:
pickle.dump(fooddict, filewriter)
except:
print("Error storing pickled dictionary")
else:
food_found = False
for key in list(fooddict):
if key.__eq__(f.name):
print("Food already stored!")
food_found = True
if not food_found:
fooddict.update({f.name: f})
with open("food.csv", 'wb') as filewriter:
try:
pickle.dump(fooddict, filewriter)
except:
print("Error storing pickled dictionary")
#classmethod
def retreiveFoodDict(cls):
with open("food.csv", 'rb') as filereader:
try:
fooddict = pickle.load(filereader)
return fooddict
except EOFError:
return("Empty File")
def findFood(title):
fooddict = Food.retreiveFoodDict()
for key in list(fooddict):
if key.__eq__(title):
continue
return fooddict[key]
s = "apple"
n = findFood(s) #does not work, it returns banana instead of apple
#which is really just grabbing whatever is the
#last object in the dictionary
m = findFood("banana") #seems to work, but only because banana is the
#last object in the dictionary
print(n) #should print an apple "food object" but instead prints a banana
print(str(m.calories)) #works, but if I said n.calories it would still print
#m.calories instead
p = Food.retreiveFoodDict() #seems to work and retrieve the dictionary
print(str(p)) #also seems to work of course
Console Output:
bananas weigh 5.0 ounces, contain 120.0 calories, and stay fresh for 3.0 days.
120.0
{'apple': <main.Food object at 0x00D2C2E0>, 'banana': <main.Food object at 0x00D36D00>}
The dictionary contains 2 food objects (apple and banana), but the print(n) statement shows a banana, not an apple. Can anyone point out why this is or what I am misunderstanding? Thank you so much!
I found the answer to my own problem. I was misusing the continue in my findFood function.
This code solved my issues.
def getFood(food_name):
fooddict = Food.retreiveFoodDict()
for key in list(fooddict):
if key.__eq__(food_name):
return fooddict[key]
What this function does is simply retrieve a dictionary of objects in a csv file and iterates through the keys until the passed key name is located. If found, the proper key name will be returned as a food object. My original mistake was using the "continue" keyword to stop the for-loop, which was returning the object directly after the one we wanted.

How to find all records(form list) from given time range in Python?

I have to have an input function which allowes me to find specyfic records (form list created before) in time range like f.ex : album range? Input-> between 3 - 5 hours, -> two album was found in ouput
This is an code that represent your question, feel free to ask question about it:
class Album:
release_time: int
def __init__(self, release_time):
self.release_time = release_time
def __repr__(self):
return f"Album({self.release_time})"
if __name__ == '__main__':
album_list = [Album(i) for i in range(10)]
user_input_min, user_input_max = (int(input('min?')), int(input('max?')))
if user_input_min > user_input_max:
print("error")
else:
album_nbr = 0
result_list = list()
for album in album_list:
if user_input_min <= album.release_time <= user_input_max:
album_nbr += 1
result_list.append(album)
print(album_list)
print(f'{album_nbr} was found')
print(result_list)
Output:
min?3
max?8
[Album(0), Album(1), Album(2), Album(3), Album(4), Album(5), Album(6), Album(7), Album(8), Album(9)]
6 was found
[Album(3), Album(4), Album(5), Album(6), Album(7), Album(8)]

How to print a dictionary made up of lines from a file in python3?

Any help is much appreciated! Thanks
I have a dictionary made up of lines extracted from a file like this:
Danny Shalev, 050-1111111, aaa#aaa.com
Gil Rom, 050-2222222, bbb#bbb.com
Tal Yakir, 050-3333333, ccc#ccc.com
Edit: my goal is for the dict to be printed out like this:
Danny Shalev - 050-1111111 - aaa#aaa.com
Gil Rom - 050-2222222 - bbb#bbb.com
Tal Yakir - 050-3333333 - ccc#ccc.com
The first name is the key, and the rest are the values.
I have written the code for converting the file lines into a dict, and I want to print out all values from my dictionary in a specific format, which would be line by line, separated by "-". I have already written the function print_person, to print it out in this format, I just want to apply this function (from the previous class) into my dict.
Here's the code:
class Person:
def __init__(self, name, phone,email):
self.name = name
self.phone = phone
self.email = email
def print_person(self):
return (str(self.name)+" - "+str(self.phone)+" - "+str(self.email))
class AddressBook:
def __init__ (self):
self.contactsdict = {}
def add(self, newContact):
self.contactsdict[newContact.name] = newContact.phone + " - " + newContact.email
def search(self, name):
return (self.contactsdict.get(name))
def addFromFile(self, fileName):
f = open("contacts.txt")
for line in f:
(key, val, val2) = line.split(",")
self.contactsdict[key] = val + " - " + val2
f.close
def printAddressBook(self):
for key, val in self.contactsdict.items():
Person.print_person
address = AddressBook() # make an instance
p1=Person("Danny Shalev","050-1111111","aaa#aaa.com")
print (p1.print_person())
address.add(p1)
address.addFromFile("contacts.txt")
address.printAddressBook()
I believe the problem is in this section, since I don't know how to use the method:
def printAddressBook(self):
for key, val in self.contactsdict.items():
Person.print_person
This
for key, val in self.contactsdict.items():
Person.print_person
deconstructs all your dictionary entries into 2 variables, one the key, the other the value. The second line is incorrrect - Person is your class, you need an instance of the class to use the defined print method on it.
You can call val.print_person() on each instance of the class Person to print each IF you store Persons in your inner dictionary. Classes are "templates" how a class is constructed - the instance must be used to call its functions. Currently your code only stores string in the internal dictionary.
To add persons to your internal Dict replace
for line in f:
(key, val, val2) = line.split(",")
self.contactsdict[key] = val + " - " + val2
with
for line in f:
(key, val, val2) = line.split(",")
self.contactsdict[key] = Person(key,val,val2) # create instances of Persons
# and store them in the dictionary by there name
# you get collisions if your file contains persons with identical names
Fixed code (this and some other errors marked with comments):
class Person:
def __init__(self, name, phone,email):
self.name = name
self.phone = phone
self.email = email
def print_person(self):
return (str(self.name) + " - " + str(self.phone) + " - " + str(self.email))
class AddressBook:
def __init__(self):
self.contactsdict = {}
def add(self, newContact):
self.contactsdict[newContact.name] = newContact # store the Person instance
# under its name as key
def search(self, name):
return (self.contactsdict.get(name))
def addFromFile(self, fileName):
f = open("contacts.txt")
for line in f:
(key, val, val2) = line.split(",")
self.add(Person(key,val,val2)) # create Person and use own add-Function
# to add it to internal dictionary
f.close
def printAddressBook(self):
for key, val in self.contactsdict.items():
print( val.print_person() ) # you need to print the output
# of print_person() - it currently only
# returns the string and does not print it
address = AddressBook() # make an instance
p1 = Person("Danny Shalev","050-1111111","aaa#aaa.com")
print(p1.print_person())
address.add(p1)
address.addFromFile("contacts.txt")
address.printAddressBook()
Search returns a person, so you can use it to change persons inside your dict:
print("")
p = address.search("Danny Shalev")
p.name = "Hallo" # change the name of the found person (the key will still be "Danny Shalev")
address.printAddressBook()
Output:
Danny Shalev - 050-1111111 - aaa#aaa.com
Gil Rom - 050-2222222 - bbb#bbb.com
Tal Yakir - 050-3333333 - ccc#ccc.com
Hallo - 050-1111111 - aaa#aaa.com # after change of searched person
Gil Rom - 050-2222222 - bbb#bbb.com
Tal Yakir - 050-3333333 - ccc#ccc.com

Resources