I have a class that contains a member object. I would like to call the member's methods as if they were methods of the container class.
The following example illustrates (however in a different context) what I would like to do.
Suppose we have two classes representing two different kinds of products: Toys and Shoes.
Each class has two methods, let's say, weight()
and description()
, which return obviusly the item's weight and the item's description.
Now I want to place these products in individual Boxes - each box will contain either a single Toy
either a single Shoe
.
I want to still be able to access the methods weight()
and description()
, however I want them to be members of the Box
instance. Also, I don't want to specifically implement the methods weight()
and description()
in the Box
class, because I don't want to have to implement more methods in the Box
class whenever a new method is added to Toy and Shoe.
Here is an example of the "end result" that would make me happy:
# Define our products
product1 = Toy('plastic gun', 200)
product2 = Shoe('black leather shoes', 500)
# Now place them in boxes
box1 = Box(product1, box_code='A1234')
box2 = Box(product2, box_code='V4321')
# I want to know the contents of the boxes
box1.description()
box2.description()
# Desired results
>> plastic gun
>> black leather shoes
My implementation idea is this.
class Product():
def __init__(self, description, weight):
self.desc = description
self.wght = weight
def description(self):
return self.desc
def weight(self):
return self.weight
class Toy(Product):
pass
class Shoe(Product):
pass
class Box(object):
def __init__(self, product, box_code):
self.box_code = box_code
self.product = product
def __getattribute__(self, name):
# Any method that is accessed in the Box instance should be replaced by
# the correspondent method in self.product
return self.product.__getattribute__(name)
However this doesn't work! If I run the "desired" example, shown in the first code block, I get an infinite recursion. So, how is the elegant way of doing this?
Notice that Box
has its own parameter box_code
, and that in the future I might want to add new methods to Toy
and Shoes
(for example, a promotional code, or whatever), without having to modify the class Box
.
Okay guys, I am eagerly awaiting for your responses.
Update: Answer to the problem Thanks to Interjay and to Mike Boer for their help.
I just had to substitute the definition of the method __getattribute__
in the class Box
by __getattr__
and it worked perfectly, as suggested by Interjay. The corrected definition of the class Box is:
class Box(object):
def __init__(self, product, box_code):
self.box_code = box_code
self.product = product
def __getattr__(self, name):
# Any method that is accessed in the Box instance should be replaced by
# the correspondent method in self.product
return self.product.__getattribute__(name)
Update: Completing the example using __setattr__
After I corrected the problem with the getattr method, I noticed that my classes weren't having the desired behavior when I wanted to set an attribute. For example, if I tried:
box1.desc = 'plastic sword'
instead of changing the description of product1 (which was incapsulated in box1), a new member called "desc" was created in box1. In order to solve this, I had to define the __setattr__
function, as shown below:
def __setattr__(self, name, value):
setattr(self.product, name, value)
However, just adding this function creates a recursive call, because in __init__
I try to assign self.product = product
' which calls the function __setattr__
, which does not find the member self.product
, so calls the function __setattr__
again, recursively ad infinitum.
In order to avoid this problem, I have to change the __init__
method in order to assign the new member using the class' dictionary. The complete definition of the class Box
is then:
class Box(object):
def __init__(self, product, box_code):
self.__dict__['product'] = product
self.box_code = box_code
def __getattr__(self, name):
# Any method that is accessed in the Box instance should be replaced by
# the correspondent method in self.product
return getattr(self.product, name)
def __setattr__(self, name, value):
setattr(self.product, name, value)
Now a funny thing... If I define first the member self.product
, as shown above, the program works normally. However, if I try to define first the member self.box_code
, the program suffers the recursive loop problem again. Does anybody know why?