简体   繁体   中英

Python: Calling class method instead of parent constructor

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?

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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM