-1

Unfortunately, I can't give you the condition of the problem, but I can briefly describe it we need to create two classes:

  1. The first class creates an exam ticket. The teacher writes the name of the subject, the correct answers to the test and the minimum percentage for successful completion.
  2. The second grade is the student's test.
class Testpaper:
    def __init__(self, subject, markscheme, pass_mark):
        self.subject = subject
        self.markscheme = markscheme
        self.pass_mark = pass_mark

class Student:
    def __init__(self, tests_taken = {}):
        self._tests_taken = tests_taken

    @property
    def tests_taken(self):
        if self._tests_taken == {}:
            self._tests_taken = "No tests taken"
            return self._tests_taken 
        else:
            return self._tests_taken
    
    def take_test(self, testpaper, answers):
        self._tests_taken = {}
        pass_mark = 0
        for answer in answers:
            if answer in testpaper.markscheme:
                percent = 100 / len(testpaper.markscheme)
                pass_mark += percent
        
        if pass_mark >= int(testpaper.pass_mark[:-1]):
            self._tests_taken[testpaper.subject] = f"Passed! ({round(pass_mark)}%)"
            return self._tests_taken
        else:
            self._tests_taken[testpaper.subject] = f"Failed! ({round(pass_mark)}%)"
            return self._tests_taken

Here's what I need to check:

paper1 = Testpaper("Maths", ["1A", "2C", "3D", "4A", "5A"], "60%")
paper2 = Testpaper("Chemistry", ["1C", "2C", "3D", "4A"], "75%")
paper3 = Testpaper("Computing", ["1D", "2C", "3C", "4B", "5D", "6C", "7A"], "75%")

student1 = Student()
student2 = Student()
paper3 = Testpaper('Computing', ['1D', '2C', '3C', '4B', '5D', '6C', '7A'], '75%')
student2 = Student()
student3 = Student()
student2.take_test(paper3, ['1A', '2C', '3A', '4C', '5D', '6C', '7B'])
print(student3.tests_taken)
student3.take_test(paper1, ['1C', '2D', '3A', '4C', '5A'])
student3.take_test(paper3, ['1A', '2C', '3A', '4C', '5D', '6C', '7B'])
print(student3.tests_taken)
print(paper3.subject)
print(paper3.markscheme)
print(paper3.pass_mark)

This is my output:

No tests taken
{'Computing': 'Failed! (43%)'}
Computing
['1D', '2C', '3C', '4B', '5D', '6C', '7A']
75%

And this is the correct output:

No tests taken
{'Maths': 'Failed! (20%)', 'Computing': 'Failed! (43%)'}
Computing
['1D', '2C', '3C', '4B', '5D', '6C', '7A']
75%

What I must change?

  • Does this answer your question? ["Least Astonishment" and the Mutable Default Argument](https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument) – buran Jan 25 '22 at 21:13
  • The mutable default argument problem is not directly related to your problem, but you should fix it. – buran Jan 25 '22 at 21:20
  • I'm sorry, but I don't understand what you mean – Anna Khishchenko Jan 25 '22 at 21:23
  • Why are you replacing the empty dict with a string in the getter? – chepner Jan 25 '22 at 21:29
  • 1
    In this line `def __init__(self, tests_taken = {}):` you have mutable default argument - a dict. If you don't understand the link I shared check also this one https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments You didn't notice the problem because you don't print all instances of Student class. – buran Jan 25 '22 at 21:35
  • @chepner this is required by the condition of the problem – Anna Khishchenko Jan 25 '22 at 21:42

2 Answers2

1

Delete the row, that resets ._tests_taken variable and it should be better :)

def take_test(self, testpaper, answers):
    self._tests_taken = {}        # this row resets the object._tests_taken
    pass_mark = 0

You don't have to reinitialise that dictionary, because in here:

self._tests_taken[testpaper.subject] = f"Passed! ({round(pass_mark)}%)"

You add (replace if taken again) the correct value anyway.

Also change your property to that:

@property
def tests_taken(self):
    if self._tests_taken == {}:
        return "No tests taken"
    else:
        return self._tests_taken

Whole code:

class Testpaper:
    def __init__(self, subject, markscheme, pass_mark):
        self.subject = subject
        self.markscheme = markscheme
        self.pass_mark = pass_mark


class Student:
    def __init__(self, tests_taken=None):
        if tests_taken is None:
            tests_taken = {}
        self._tests_taken = tests_taken

    @property
    def tests_taken(self):
        if self._tests_taken == {}:
            return "No tests taken"
        else:
            return self._tests_taken

    def take_test(self, testpaper, answers):
        pass_mark = 0
        for answer in answers:
            if answer in testpaper.markscheme:
                percent = 100 / len(testpaper.markscheme)
                pass_mark += percent

        if pass_mark >= int(testpaper.pass_mark[:-1]):
            self._tests_taken[testpaper.subject] = f"Passed! ({round(pass_mark)}%)"
            return self._tests_taken
        else:
            self._tests_taken[testpaper.subject] = f"Failed! ({round(pass_mark)}%)"
            return self._tests_taken


if __name__ == '__main__':
    paper1 = Testpaper("Maths", ["1A", "2C", "3D", "4A", "5A"], "60%")
    paper2 = Testpaper("Chemistry", ["1C", "2C", "3D", "4A"], "75%")
    paper3 = Testpaper("Computing", ["1D", "2C", "3C", "4B", "5D", "6C", "7A"], "75%")

    student1 = Student()
    student2 = Student()
    paper3 = Testpaper('Computing', ['1D', '2C', '3C', '4B', '5D', '6C', '7A'], '75%')
    student2 = Student()
    student3 = Student()
    student2.take_test(paper3, ['1A', '2C', '3A', '4C', '5D', '6C', '7B'])
    print(student3.tests_taken)
    student3.take_test(paper1, ['1C', '2D', '3A', '4C', '5A'])
    student3.take_test(paper3, ['1A', '2C', '3A', '4C', '5D', '6C', '7B'])
    print(student3.tests_taken)
    print(paper3.subject)
    print(paper3.markscheme)
    print(paper3.pass_mark)
NixonSparrow
  • 6,130
  • 1
  • 6
  • 18
  • that's what knocks me out if I do as you say: `self._tests_taken[testpaper.subject] = f"Passed! ({round(pass_mark)}%)" TypeError: 'str' object does not support item assignment` – Anna Khishchenko Jan 25 '22 at 21:20
  • Oh yes, didn't see that: `self._tests_taken = "No tests taken"`. Change it as I edited and it will work :) – NixonSparrow Jan 25 '22 at 21:28
  • it doesn't work either: `{'Maths': 'Passed! (80%)', 'Chemistry': 'Failed! (25%)', 'Computing': 'Failed! (43%)'} {'Maths': 'Failed! (20%)', 'Chemistry': 'Failed! (25%)', 'Computing': 'Failed! (43%)'} Computing ['1D', '2C', '3C', '4B', '5D', '6C', '7A'] 75%` – Anna Khishchenko Jan 25 '22 at 21:31
  • I really only changed what you specified, but this is not the answer I need, this is what the correct answer should look like: `No tests taken {'Maths': 'Failed! (20%)', 'Computing': 'Failed! (43%)'} Computing ['1D', '2C', '3C', '4B', '5D', '6C', '7A'] 75%` – Anna Khishchenko Jan 25 '22 at 21:47
  • 1
    I added the whole working code to the answer. It may need also change in the `__init__`. – NixonSparrow Jan 25 '22 at 21:51
  • thank you very much, it really worked – Anna Khishchenko Jan 25 '22 at 21:55
0

Just change tests taken to read like so:

def tests_taken(self):
        if self._tests_taken == {}:
            return "No tests taken"
        else:
            return self._tests_taken

And change __init__ to look like this:

def __init__(self, ):
        self._tests_taken = {}

Full code is this:

class Testpaper:
    def __init__(self, subject, markscheme, pass_mark):
        self.subject = subject
        self.markscheme = markscheme
        self.pass_mark = pass_mark

class Student:
    def __init__(self):
        self._tests_taken = {}

    @property
    def tests_taken(self):
        if self._tests_taken == {}:
            return "No tests taken"
        else:
            return self._tests_taken
    
    def take_test(self, testpaper, answers):  
        self._tests_taken == {}
        pass_mark = 0
        for answer in answers:
            if answer in testpaper.markscheme:
                percent = 100 / len(testpaper.markscheme)
                pass_mark += percent
        
        if pass_mark >= int(testpaper.pass_mark[:-1]):
            self._tests_taken[testpaper.subject] = f"Passed! ({round(pass_mark)}%)"
        else:
            self._tests_taken[testpaper.subject] = f"Failed! ({round(pass_mark)}%)"

paper1 = Testpaper("Maths", ["1A", "2C", "3D", "4A", "5A"], "60%")
paper2 = Testpaper("Chemistry", ["1C", "2C", "3D", "4A"], "75%")
paper3 = Testpaper("Computing", ["1D", "2C", "3C", "4B", "5D", "6C", "7A"], "75%")

student1 = Student()
student2 = Student()
paper3 = Testpaper('Computing', ['1D', '2C', '3C', '4B', '5D', '6C', '7A'], '75%')
student2 = Student()
student3 = Student()
student2.take_test(paper3, ['1A', '2C', '3A', '4C', '5D', '6C', '7B'])
print(student3.tests_taken)
student3.take_test(paper1, ['1C', '2D', '3A', '4C', '5A'])
student3.take_test(paper3, ['1A', '2C', '3A', '4C', '5D', '6C', '7B'])
print(student3.tests_taken)
print(paper3.subject)
print(paper3.markscheme)
print(paper3.pass_mark)

Output:

No tests taken
{'Maths': 'Failed! (20%)', 'Computing': 'Failed! (43%)'}
Computing
['1D', '2C', '3C', '4B', '5D', '6C', '7A']
75%
Eli Harold
  • 2,280
  • 1
  • 3
  • 22