Sunday, December 19, 2021

Using Spinoza with Python Objects (For in-class exercises)

During the COVID-19 pandemic, I started using Spinoza (https://spinoza.cs.brandeis.edu/) in Intro Programming.  Spinoza lets students try out solving problems in Python.  They get immediate feedback and there's lots of additional pedagogical features.

It uses Brython to run the code.  When it loads each page, parameters for functions are passed as strings.  If you try to create the objects in the Test Generator box, they won't pass correctly when Spinoza executes the tests.  Instead, you have to generate them using additional code that you put in the Solution box.  For example, if you're asking students to write a get_height() method or function for a Monkey class, you have to set things up this way:

  • Use a different name in the Method Name field.  I always just append "_wrapper" to the end.  (E.g. get_height_wrapper.)

  • For the number of parameters, use the total number of primitives you'll need to create any objects for the subject and all parameters.

  • Still put the original function/method header in the scaffolding box.  E.g. def get_height():  If they're writing a method, put it inside the class.  If there are other methods they'll need (__init__ or __str__) then you can include those here too.

class Monkey(object):

    '''Models a monkey.  Attributes: age, height, num_bananas.'''

    def get_height(self):

 

  • In the solution box, there are a bunch of additional things to do:

    • Add a function that creates an instance of the object:

def create_monkey(age, height, num_bananas):

    monkey = Monkey()

    monkey.age = age

    monkey.height = height

    monkey.num_bananas = bananas

    return monkey 

(This will change a lot if they've already created an __init__ and you include that in the scaffolding.)
    • If you didn't create the class above, create it here.  Also include any other classes you might need that you didn't put in the scaffolding.

    • Add the definition of the wrapper.  It should create the objects, then call the function/method that the student is writing.

def get_height_wrapper(age, height, num_bananas):

    monkey = create_monkey(age, height, num_bananas)

    return monkey.get_height()

    • Add your correct version of the requested function.  (E.g. my_get_height().)  If they're writing a method, you'll have to write this as a function instead.

def my_get_height(monkey):

    return monkey.height

    • Add the solution function, which does the same thing as the wrapper, except that it calls your function instead of the student's.

def solution(age, height, num_bananas):

    monkey = create_monkey(age, height, num_bananas)

    return my_get_height(monkey)


It took me a long time to get this working back in 2020, so I hope this is helpful for other people that want to use Spinoza!