hi. wondering if someone can take a few min to help me out.

Well im taking this opencourseware from MIT, intro to programing. I got this assignment

http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00-introduction-to-computer-science-and-programming-fall-2008/assignments/pset9.pdf

and I could do it on my own... the only problem is I dont understand what the hell they want me to do for problem 2.

Its like... it doesnt tell me what the input should be exactly. I dont think its clear. I get that they want me to make a set of circles, squares and triangles. So I figured it would be best to make 3 lists and then put in the specs (base height for triangle, radius for circle, side for square) as tuples inside the lists.

But then I get to this point and im like.... What is the input thats going in? Are they a bunch of unnamed circles and squares? If a triangle has 2 attributes and a circle has 1, how can I enter them into the method? If I enter a circle wont it put up an error that says the method needs 2 variables? (because triangle is 2 variables).

Im really confused. I managed to do all of the others without help, but this one is too confusing. Please help someone, otherwise ill just skip it.

Recommended Answers

All 17 Replies

What is template file ps9.py?

I think the set should contain Triangle, Square etc objects, values of those come from the implementation of those classes. If two of the shapes are not ever same as mentioned in description, it enables you to use regular set.

So for me this looks like only putting objects to a regular set and yielding them one by one in __iter__, __str__ is just loop over set and print in seperate lines (would be good to put empty line before and after as separator) sorted.

thanks for the quick reply man, but what do you mean by regular set?

heres ps9 :
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00-introduction-to-computer-science-and-programming-fall-2008/assignments/ps9.py

heres shapes(if you want it):
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00-introduction-to-computer-science-and-programming-fall-2008/assignments/shapes.txt

I think i might be just getting confused by something stupid. Im going to review/watch the lecture again/think about it more before I keep asking questions. But yeah still any help is definitly appreciated so thanks alot.

To express my opinion frankly, the instructions are stupid. I'll explain why later.

However, let me see if I can help.

We're looking at Problem 2?

In this problem you are implementing a custom container class to hold shape objects. The main purposes of this container are to ensure that each shape is unique, provide a method to return a string representation of the shapes in the container, and to provide a method to iterate over the shapes in the container.

You won't have to worry about creating a list of several element tuples. Each shape is represented by a shape object. The shape classes are in ps9.py. When you add a shape to the container you'll be adding a shape object not the shape's data.

If you were making a program you would import the ps9 module to provide access to the shape classes. Then you can add a shape to a ShapeSet. (Reading the ps9 module some more I see that the ShapeSet should be in the ps9 module, but let's keep it in the script for the moment.)

import ps9

class ShapeSet:

    def addShape(self, sh):
        #Add shape 'sh' to the container after ensuring that it is unique.
        pass

myShapeSet = ShapeSet()
mySquare = ps9.Square(9.5)
myShapeSet.addShape(mySquare)

Luckily each shape has a '__eq__' method you can call to compare it to another shape. (And you won't have to bother to ensure that each shape is of the same type. The '__eq__' method of each shape handles the difference.) Remember, any object that has an '__eq__' method can just as easily be compared with '=='.

Now you will need a container to hold the shapes. When you add a shape you can iterate over the container of shapes and if the exact shape you are trying to add is in the container you can return. (That ensures the shape won't be added.) If it isn't then the next part of the function would append the shape to the container.

Obviously it is important for you to do your own homework. I'll leave it to you to:

1) Determine which type of container to use to hold the shapes.
2) Learn how to make the container an attribute of the ShapeSet object. (Hint: When you initialize an object you can specify default attributes and provide default values for those attributes.)
3) Determine how to iterate over the container and compare the shape being added to the shapes currently in the container.

You'll also need to implement the ShapeSet iterator. The simplest way would be to return the call to the internal container's iterator. However, the intent of the exercise may be to get you to implement the internal workings of an iterator. That I do not know how to do.

The final thing you will need to implement is the method to return a string representation of the set. One way to do it is iterate over the shapes in the container and to create a string representation of the shape. Append this representation to a temporary list and when you get ready to return the string for the whole container create a joined string from the list.

class ShapeSet:

    def __str__(self):
        temp = []
        for shape in self.shapes:
            #Form the string representation of the shape and append it to temp.
            pass
        #Return the string representing the whole set.
        return ''.join(temp)

If I'm reading the problem correctly accomplishing all of that should solve the goal of the problem.

Now let me tell you how it should be done so you won't be a screwed up programmer the rest of your life. :) This may not be acceptable to turn in because it's not what the assignment stipulates. I'd still show your instructor.

Classes can inherit attributes and methods from other classes. This allows common functionality without rewriting the attributes and methods inherited from the parent class. The ps9 module actually has examples of this because each specific type of shape inherits from a general shape class.

If you wanted to create a set of shapes you could do the exact same thing by inheriting the builtin 'set' type that ensures that all of its elements are unique, provides an iterator, and even prints out a string representation of the set. In fact, if your set of shapes only needs to do only those things you don't even need to implement a custom class. I only show this example assuming that the ShapeSet class will do other unique things.

import ps9
#ShapeSet inherits from set as indicated by the class or type in the parentheses.
class ShapeSet(set):
    pass

myshapeset = ShapeSet()
myshapeset.add(ps9.Square(9.5))
myshapeset.add(ps9.Circle(4.2))
myshapeset.add(ps9.Square(9.5))
#Prints the set. Will only be two shapes - one square and one circle. The second square was not unique.
print(myshapeset)

The '__str__' method on the set class prints a list of the string representations of the objects in the set. That means that as long as each object in the set has a proper '__str__' or '__repr__' method (informative string representation of technical details of the object) then the set will return a proper string.

Unfortunately the shape classes in ps9 don't have a string method yet. For the square:

class Square(Shape):

    def __str__(self):
        return 'Square with side {0}.'.format(self.side)

For the circle:

class Circle(Shape):

    def __str__(self):
        return 'Circle with radius {0}.'.format(self.radius)

Now putting it together:

import ps9

class ShapeSet(set):
    pass

myshapeset = ShapeSet()
myshapeset.add(ps9.Square(9.5))
myshapeset.add(ps9.Circle(4.2))
myshapeset.add(ps9.Square(9.5))
print(myshapeset)

ShapeSet({'Square with side 9.5.', 'Circle with radius 4.2.'})

Unfortunately the shape classes in ps9 don't have a string method yet. For the square:

class Square(Shape):

    def __str__(self):
        return 'Square with side {0}.'.format(self.side)

For the circle:

class Circle(Shape):

    def __str__(self):
        return 'Circle with radius {0}.'.format(self.radius)

Now putting it together:

import ps9

class ShapeSet(set):
    pass

myshapeset = ShapeSet()
myshapeset.add(ps9.Square(9.5))
myshapeset.add(ps9.Circle(4.2))
myshapeset.add(ps9.Square(9.5))
print(myshapeset)

Unfortunately small mistake in your excellent reply, the classes do define __str__ method, but the needed __repr__ method is missing. You can copy __str__ method and change the name. Generally though idea of repr is that you can eval the string it and get the original object (i.e. what you need to give initialize object in string form), not verbal discription of the object.

So I would define __repr__ for square like this (using style of .format from original module):

def __repr__(self):
        return 'Square({0})'.format(self.side)

And so on..

Result:

from ps9 import *

class ShapeSet(set):
    pass

myshapeset = ShapeSet()
myshapeset.add(Square(9.5))
myshapeset.add(Circle(4.2))
myshapeset.add(Square(9.5))

## repr defined with simple object init form object(initparameters)
print(myshapeset)

for i in sorted(myshapeset):
    print eval(repr(i)) ## proper repr test
"""Output:
ShapeSet([Square(9.5), Circle(4.2), Square(9.5)])
Circle with radius 4.2
Square with side 9.5.
Square with side 9.5.
"""

Unfortunately set does not seem to deal properly with equality, but has two same size squares! But maybe this is right solution as they are not same object exactly.

Request needed this sorted output from iteration so we would need kind of 'sortedset'.

This thing of sets was what I was expressing maybe not so clear and at least not this exactly in my previous post.

commented: Good work. +1

I made another error. ps9 does have '__str__' methods for some of the classes.

I should have tested what I was suggesting. It didn't work for me. I assumed it would but I made an ass out of myself.

I'm getting a different bug though. My interpreter is complaining that the Circle type is not hashable.

Maybe fixing this would solve the problem? I'll get back when I learn what hashing is all about.

P.S. Nice work importing all from ps9. Me having to type ps9 over and over should have been a good indication to import the names that I needed.

You are also right about '__repr__'. However, for this assignment the set's '__str__' method does need to be overwritten.

OK. Hash returns an integer value representing an object. Two objects with the same value will return the same hash value, but the opposite is not necessarily true. Two objects with the same hash value may not necessarily have the same value. However, since set uses this value it must be accurate enough for the purposes of set.

I'm thinking that if I implement a '__hash__' method on each shape then set will work properly. I'm thinking that since tuples are hashable I should make each shape return the hash value for the tuple of its data.

class Square(Shape):

    def __hash__(self):
        return hash((type(self), self.side))

class Circle(Shape):

    def __hash__(self):
        return hash((type(self), self.radius))

I tested sets composed of shape object's with this method. They worked as specified. Only shapes with unique values were added to the set.

from ps9 import Square, Circle

myset = set([Square(9.5), Circle(4.2), Square(9.5)])
print(myset)

That should result in a representation of the contents. One circle object and one square object. (I overrode the '__repr__' methods to ensure that they had the values I specified. They did.)

P.S. I skimmed over the problem set. I'm not seeing any stipulation that the set needs to be sortable. Where did you see it?

Wow. Thanks alot to everyone who helped me out. Its too late now though, im going to check this out tomorow first chance I get. But yeah, thanks so much.

P.S. I skimmed over the problem set. I'm not seeing any stipulation that the set needs to be sortable. Where did you see it?

It said that the print out should be 'categorized by shape', which is easiest to implement by sorting the shapes in sequence as their string start the same way.

And it said different in sence of '==', so it could be that multiple same size object can exist in the set (really shape should have location also, maybe rotation). I think best way of dealing souch unsure situation is quote the point in assignment in comment and write 'this I interpreted to mean that...'

My full code:
ps9.py (shapeset replaced from set solution)

# 6.00 Problem Set 9
#
# Name:
# Collaborators:
# Time:

from string import *

class Shape(object):
    def area(self):
        raise AttributeException("Subclasses should override this method.")

class Square(Shape):
    def __init__(self, h):
        """
        h: length of side of the square
        """
        self.side = float(h)
    def area(self):
        """
        Returns area of the square
        """
        return self.side**2
    def __str__(self):
        return 'Square with side {0}.'.format(self.side)

    def __repr__(self):
        return 'Square({0})'.format(self.side)

    def __eq__(self, other):
        """
        Two squares are equal if they have the same dimension.
        other: object to check for equality
        """
        return type(other) == Square and self.side == other.side

class Circle(Shape):
    def __init__(self, radius):
        """
        radius: radius of the circle
        """
        self.radius = float(radius)

    def area(self):
        """
        Returns approximate area of the circle
        """
        return 3.14159*(self.radius**2)

    def __str__(self):
        return 'Circle with radius ' + str(self.radius)
    
    def __repr__(self):
        return 'Circle({0})'.format(self.radius)
    
    def __eq__(self, other):
        """
        Two circles are equal if they have the same radius.
        other: object to check for equality
        """
        return type(other) == Circle and self.radius == other.radius

#
# Problem 1: Create the Triangle class
#
## TO DO: Implement the `Triangle` class, which also extends `Shape`.

#
# Problem 2: Create the ShapeSet class
#
## TO DO: Fill in the following code skeleton according to the
##    specifications.
class ShapeSet(set):
    pass

#
# Problem 3: Find the largest shapes in a ShapeSet
#
def findLargest(shapes):
    """
    Returns a tuple containing the elements of ShapeSet with the
       largest area.
    shapes: ShapeSet
    """
    ## TO DO

#
# Problem 4: Read shapes from a file into a ShapeSet
#
def readShapesFromFile(filename):
    """
    Retrieves shape information from the given file.
    Creates and returns a ShapeSet with the shapes found.
    filename: string
    """
    ## TO DO

Test. with repr set according to Python recommendations to be evaluable (good point if you want to return code that matches the assignment: we are helping, not doing)

from ps9 import *

myshapeset = ShapeSet()
myshapeset.add(Square(9.5))
myshapeset.add(Circle(4.2))
myshapeset.add(Square(9.5))

## repr defined with simple object init form object(initparameters)
print(myshapeset)

for i in sorted(myshapeset):
    print eval(repr(i)) ## proper repr test
"""Output:
ShapeSet([Square(9.5), Circle(4.2), Square(9.5)])
Circle with radius 4.2
Square with side 9.5.
Square with side 9.5.
"""

That's not what I would do. Two integer objects are equal if and only if their numeric value is the same and unequal if and only if their numeric value is different. That isn't dependent upon their existence as an object. Looking at the '__eq__' method on the shapes it checks only that both shape objects are the same type and that their dimensions are equal. Two shapes are equal if and only if they are the same type and the same size. Two shapes are unequal if and only if they are a different type or they have a different size.

But the decision isn't up to me. That's just what I would think if I were in the poster's position.

Could be problem with the thing that the side's length is floating number. It is tricky dealing with equality of floats.

Nice catch.

Python's builtin rounding function can help with that. Trouble is determining the number of significant digits for rounding.

http://docs.python.org/release/2.5.4/lib/typeiter.html

Im trying to figure out why I need to put in my own __iter__ method. Why?

here it an example of one :

class Faculty(object):
    def __init__(self):
        self.names = []
        self.IDS=[]
        self.members = []
        self.place= none
    def __iter__(self):
        self.place = 0
        return self

    def next(self):
        if self.place >= len(self.names):
            raise stopIteration
        self.place +=1
        return self.members[self.place-1]

basicly... the teach and the problem says you need to put in __iter__, but the teach never really explained why __iter__ is needed, or what it does. Im thinkings its the same thing as for i in some list: print i. Why do I need to write my own iter method? Where will my methods for ps9 be calling it if i did create one?

(was not sure if I should create a new thread to ask about this)

oh yeah, thanks for the help also. this is what I wrote so far (have not been copying your code, dont want to cheat. but yeah I wrote it and dont see a reason for __iter__ so thats what I need help with now.

# 6.00 Problem Set 9
#
# Name:
# Collaborators:
# Time:

from string import *

class Shape(object):
    def area(self):
        raise AttributeException("Subclasses should override this method.")

class Square(Shape):
    def __init__(self, h):
        """
        h: length of side of the square
        """
        self.side = float(h)
    def area(self):
        """
        Returns area of the square
        """
        return self.side**2
    def __str__(self):
        return 'Square with side ' + str(self.side)
    def __eq__(self, other):
        """
        Two squares are equal if they have the same dimension.
        other: object to check for equality
        """
        return type(other) == Square and self.side == other.side

class Circle(Shape):
    def __init__(self, radius):
        """
        radius: radius of the circle
        """
        self.radius = float(radius)
    def area(self):
        """
        Returns approximate area of the circle
        """
        return 3.14159*(self.radius**2)
    def __str__(self):
        return 'Circle with radius ' + str(self.radius)
    def __eq__(self, other):
        """
        Two circles are equal if they have the same radius.
        other: object to check for equality
        """
        return type(other) == Circle and self.radius == other.radius

class Triangle(Shape):
    def __init__(self, b, h):
        self.base = float(b)
        self.height = float(h)
    def area(self):
        return (self.base*self.height)/2.0
    def __str__(self):
        return 'Triangle with base ' + str(self.base) + ' and height ' + str(self.height)
    def __eq__(self, other):
        return type(other) == Triangle and self.base == other.base and self.height == other.heig
#
# Problem 2: Create the ShapeSet class
#
## TO DO: Fill in the following code skeleton according to the
##    specifications.

class ShapeSet():
    def __init__(self):
        """
        Initialize any needed variables
        """
        self.THEset=[]
    def addShape(self, sh):

        """
        Add shape sh to the set; no two shapes in the set may be
        identical
        sh: shape to be added
        """
        o=0
        if len(self.THEset) > 0:
            for i in self.THEset:
                if i == sh:
                    o+=1
        if o == 0:
            self.THEset.append(sh)
        else : print 'there is already an equal object in this set'
        self.THEset=sorted(self.THEset)

    def __iter__(self):
        """
        Return an iterator that allows you to iterate over the set of
        shapes, one shape at a time
        """

    def __str__(self):
        """
        Return the string representation for a set, which consists of
        the string representation of each shape, categorized by type
        (circles, then squares, then triangles)
        """
        string = 'set = '
        for i in self.THEset:
            string +=str(i)
            string +=', '
        return string

__iter__ is to get for loop and other iteration to work with container class or to walk through all atributes of single object.
Generally it does not return values, but uses generator yield statement to give values one by one.

but it works even if I dont write the code for it. Does that mean it just uses some version python already wrote when I use a for loop?

but it works even if I dont write the code for it. Does that mean it just uses some version python already wrote when I use a for loop?

I proved with this main from my earlier code adapted add -> addShape.

myshapeset = ShapeSet()
myshapeset.addShape(Square(9.5))
myshapeset.addShape(Circle(4.2))
myshapeset.addShape(Square(9.5))

## repr defined with simple object init form object(initparameters)
print(myshapeset)

for i in sorted(myshapeset):
    print i

Result was:

there is already an equal object in this set
set = Circle with radius 4.2, Square with side 9.5, 

Traceback (most recent call last):
  File "D:/test/ps9_sol.py", line 119, in <module>
    for i in sorted(myshapeset):
TypeError: __iter__ returned non-iterator of type 'NoneType'
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.