Objects can be part of other objects. For instance, a rectangle can be
defined as a point that indicates its top-left corner, a width, and a
height. As such, the class Rectangle can be defined as follows:
class Point:
def __init__( self, x=0.0, y=0.0 ):
self.x = x
self.y = y
def __repr__( self ):
return "({}, {})".format( self.x, self.y )
class Rectangle:
def __init__( self, point, width, height ):
self.point = point
self.width = width
self.height = height
def __repr__( self ):
return "[{},w={},h={}]".format( self.point, self.width,
self.height )
p = Point( 3.5, 5.0 )
r = Rectangle( p, 4.0, 2.0 )
print( r )
In this definition, the Rectangle object contains a Point object.
Create a different version of the Rectangle class, that instead of the
top-left corner point, width, and height, gets the top-left corner point
and the lower-right corner point.
Below is a copy of the code above, expanded with a few extra lines that
make a change to the Point p.
class Point:
def __init__( self, x=0.0, y=0.0 ):
self.x = x
self.y = y
def __repr__( self ):
return "({}, {})".format( self.x, self.y )
class Rectangle:
def __init__( self, point, width, height ):
self.point = point
self.width = width
self.height = height
def __repr__( self ):
return "[{},w={},h={}]".format( self.point, self.width,
self.height )
p = Point( 3.5, 5.0 )
r = Rectangle( p, 4.0, 2.0 )
print( r )
p.x = 1.0
p.y = 1.0
print( r )
When you run this code, you see that by changing p, the Rectangle r
is also changed. The point that it contains, is actually a reference to
the point that was passed to the __init__() method. Like lists,
dictionaries, and sets, all the objects that are instances of classes
that you define, are “passed by reference” to functions and methods.
Therefore, Rectangle r gets created with a reference to p. This way,
relationships between objects can be represented.
You do not always want this. In fact, it is unlikely that you would want
a Rectangle object to have a relationship with the point that is
indicated as its upper left corner. How can you solve that? You can
solve it by creating a copy of the object. You can do this using the
copy module. As discussed before, the copy() function of the copy
module creates a shallow copy; if you want a deep copy, you have to use
the deepcopy() function. For Points this is not needed, as there is
no difference between shallow and deep copies of instances of this
class.
from copy import copy
class Point:
def __init__( self, x=0.0, y=0.0 ):
self.x = x
self.y = y
def __repr__( self ):
return "({}, {})".format( self.x, self.y )
class Rectangle:
def __init__( self, point, width, height ):
self.point = copy( point )
self.width = width
self.height = height
def __repr__( self ):
return "[{},w={},h={}]".format( self.point, self.width,
self.height )
p = Point( 3.5, 5.0 )
r = Rectangle( p, 4.0, 2.0 )
print( r )
p.x = 1.0
p.y = 1.0
print( r )