0

Say I have the following class definition:

class WorldObject(pygame.sprite.Sprite):

    @classmethod
    def fromImgRect(cls, rect, image, collideable = True):
        return cls(rect.left, rect.top, rect.width, rect.height, image, collideable)        

    def __init__(self, x, y, w, h, image, collideable = True):
        self.rect = pygame.rect.Rect(x,y,w,h)
        self.collideable = collideable
        self.image = image

Then I have the following child class:

class Doodad(WorldObject):    
    def __init__(self,c1x, c1y, c2x, c2y, color = (200,0,180)):
        self.color = color
        self.rect = orderPoints(c1x, c1y, c2x, c2y)
        x1 = self.rect.left
        y1 = self.rect.top
        w = self.rect.width
        h = self.rect.height
        super(Doodad, self).__init__(x1,y1,w,h,self.surface, False)

This works just fine, however it is annoying to have to unpack self.rect like this all throughout my code, instead of just doing it once in the class method. This is happening in many places throughout my project, where several of my methods return a rectangle object, but I need to pass coordinates to a super constructor. It doesn't look like its possible to have everything return either coordinates or a rectangle, sometimes it just makes more sense to do one or the other. Since python doesn't support overloading methods, I'd like to be able to use the class method to initialize the object. However I haven't been able to figure out the syntax. Is this possible? If so, how?

Trevor
  • 995
  • 3
  • 10
  • 25
  • Why not alter `WorldObject` to initialise from a `Rect` directly, and make `from_coords` the class method? Or have `WorldObject.__init__` handle either a `Rect` or a tuple of coordinates, either as separate parameters or with `isinstance`? – jonrsharpe Jul 16 '14 at 08:07
  • The problem with switching the current class method and __init__ is that sometimes the situation is reversed, and I have a set of coordinates instead of a rect. I might try using the isinstance solution, I'll have to give it some more thought but that is an interesting idea. – Trevor Jul 16 '14 at 08:25
  • You could also consider `__new__` or a factory - see e.g. [here](http://stackoverflow.com/q/674304/3001761). – jonrsharpe Jul 16 '14 at 11:01

1 Answers1

0

In your situation, I would add a method for "sub-initializing". This would post-process the given data:

class WorldObject(pygame.sprite.Sprite):

    @classmethod
    def fromImgRect(cls, rect, *a, **k):
        return cls(rect.left, rect.top, rect.width, rect.height, *a, **k)

    def __init__(self, x, y, w, h, image, collideable=True):
        self._init_coords(x, y, w, h)
        self.collideable = collideable
        self.image = image

    def _init_coords(self, x, y, w, h):
        self.rect = pygame.rect.Rect(x,y,w,h)

Then you can have the following child class:

class Doodad(WorldObject):
    def _init_coords(self, c1x, c1y, c2x, c2y):
        self.rect = orderPoints(c1x, c1y, c2x, c2y)

    def __init__(self,c1x, c1y, c2x, c2y, color=(200, 0, 180)):
        super(Doodad, self).__init__(c1x, c1y, c2x, c2y, self.surface, False)
        self.color = color

Besides, you might want to have

def unpack_rect(rect):
    return rect.left, rect.top, rect.width, rect.height

You can even have

class WorldObject(pygame.sprite.Sprite):

    def __init__(self, *a, **k):
        if hasattr(a[0], 'left'):
            rect = a[0]
            self._init_coords(rect.left, rect.top, rect.width, rect.height)
            rest = a[1:]
        else:
            self._init_coords(*a[0:4])
            rest = a[4:]
        self._init_rest(*rest, **k)

    def _init_coords(self, x, y, w, h):
        self.rect = pygame.rect.Rect(x,y,w,h)

    def _init_rest(self, image, collideable=True):
        self.collideable = collideable
        self.image = image


class Doodad(WorldObject):
    def _init_coords(self, c1x, c1y, c2x, c2y):
        self.rect = orderPoints(c1x, c1y, c2x, c2y)

    def _init_rest(color=(200, 0, 180)):
        super(Doodad, self)._init_rest(self.surface, False)
        self.color = color

(I didn't change self.surface here, but it is not defined at this moment. You should change that.)

glglgl
  • 89,107
  • 13
  • 149
  • 217