Reputation: 137
Okay so I have to make two classes (in two different scripts), both called Block, which store information about the position and size of a rectangular block. Version 1 should have attributes to store the coordinates of the center of the block (either as separate x- and y-coordinates or as a pair* of numbers) and for the width and height of the block. Version 2 should have attributes to store the coordinates of the bottom-left corner (the "SW" corner) and the coordinates of the upper-right corner (the "NE" corner).
So I know how I would set up the constructor for each one separately, but for this assignment both versions should have a constructor that will take either a pair of coordinates for the center along with the width and height (as floating point numbers), or two pairs of coordinates representing any two opposite corners of the block. This is what I tried so far:
class Block:
"""Stores information about the position and size of a rectangular block.
Attributes: x-coordinate (int), y-coordinate (int), width (int), height (int) OR northeast corner (int) and southwest corner (int)"""
def __init__(self, center = '', width = '', height = '', SW = '', NE = ''):
"""A constructor that assigns attributes to the proper variables
Block, tuple, tuple -> None"""
self.center = center
self.width = width
self.height = height
self.SW = SW
self.NE = NE
but I'm pretty sure that doesn't actually work the way I want it to. Basically I need to be able to input either a set of variables as the center, width and height, OR I need to input the two corners. Is there a way to do this?
Upvotes: 0
Views: 104
Reputation: 1534
You are almost there. Try something like this...
class Block:
def __init__(self, center = '', width = '', height = '', SW = '', NE = ''):
if SW != '' or NE != '':
if SW == '' and NE == '': # usage error
return None # throw an exception here
self.center = getCenterFromCorners(SW, NE) # ((sw[0]+ne[0])/2, ...)
self.width = getWidthFromCorners(SW, NE) # abs(sw[0]-ne[0])
self.height = getHeightFromCorners(SW, NE) # abs(sw[1]-ne[1])
else:
if center == '' or width == '' or '' height == '':
return None # throw exception
self.center = center
self.width = width
self.height = height
return self
# usage: block1 and block2 should be similar
block1 = Block(center=(10,20), height=2, width=4)
block2 = Block(SW=(9,18), NE=(11,22))
I am sure you can replace the code for getCenterFromCorners(), ...
Upvotes: 0
Reputation: 532418
You have to examine which arguments are passed to the function and act accordingly. Typically, what you want to do is pick one canonical representation to use to actually store the data, and have __init__
convert whatever arguments are passed to it to the canonical form. For example:
# Use None to represent missing data. Think about it: "hello" is not a
# valid width; neither is "".
def __init__(self, center=None, width=None, height=None, SW=None, NE=None):
"""A constructor that assigns attributes to the proper variables
Block, tuple, tuple -> None"""
if center is not None and width is not None and height is not None:
# If either SW or NE is given, ignore them
self.center = center
self.width = width
self.height = height
elif SW is not None and NE is not None:
# _convert_corners is a helper function you define
self.center, self.width, self.height = _convert_corners(SW, NE)
else:
# Not entirely true. Give width, height, and one corner, you
# could reconstruct the center, but this is just an example.
raise ValueError("Insufficient information to construct Block")
You can use properties to compute other attributes on the fly, rather than store them redundantly:
@property
def SW(self):
# return the south-west corner as computed from
# self.center, self.height, and self.width
@property
def NE(self):
# return the north-east corners computed from
# self.center, self.height, self.width
Another approach is to use class methods to supply alternate constructors.
def __init__(self, center, width, height):
"Define a block by its center, width, and height"
self.center = center
self.width = width
self.height = height
@classmethod
def from_corners(self, sw, ne):
"Define a block by two corners"
c, w, h = _convert_corners(sw, ne)
return Block(c, w, h)
In use:
# For demonstration purposes, I'm assuming points like the center
# and the corners are simple tuples of integer coordinates
b1 = Block((10, 50), 5, 7)
b2 = Block.from_corners((20, 30), (40, 70))
Upvotes: 2