• Advertisement
Sign in to follow this  

Python objects within an object - help

This topic is 3959 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm having trouble making an object in python within another object that is not shared with other main objects. Example: class HEAD: nose = 4 class HUMAN: head = HEAD() height = 4 x = HUMAN() x.head.nose >>> 4 x.head.nose = 20 x.head.nose >>> 20 y = HUMAN() y.head.nose >>> 20 How do I change the code so that y.head.nose retains its original value of 4?

Share this post


Link to post
Share on other sites
Advertisement
Right now, "nose","head" and "height" are class attributes. They belong to the classes HEAD and HUMAN respectively, not to instances of those classes(objects). When you do "y.head" or "x.head", you actually access the class attribute "HUMAN.head" both times. What you actually need is data attributes:


class HEAD:
def __init__(self):
self.nose=4

class HUMAN:
def __init__(self):
self.head=HEAD()
self.height=4



Share this post


Link to post
Share on other sites
This should do the trick:


class HEAD:
def __init__(self):
self.nose = 4

class HUMAN:
def __init__(self):
self.head = HEAD()
self.height = 4


EDIT: beaten to it

Share this post


Link to post
Share on other sites
Quote:
Original post by seanmusgrave
How do I change the code so that y.head.nose retains its original value of 4?

Assign it to an instance of the class and not to the class as a whole:

class Head:
def __get_nose(self):
return self.__nose

def __set_nose(self, value):
self.__nose = value

def __init__(self):
self.__nose = 4

nose = property(__get_nose, __set_nose) # nose can not be deleted

class Human:
def __get_head(self):
return self.__head

def __get_height(self):
return self.__height

def __set_height(self, value):
if value < 0:
raise ValueError("A Human can not have a negative height")
self.__height = value

def __init__(self):
self.__height = 4
self.__head = Head()

head = property(__get_head) # head can not be set or deleted
height = property(__get_height, __set_height)


In addition to making nose an instance member (by assigning it to the dictionary of self in __init__), I made it a property to show you how you can control access to a member. Try the following:

x = Human()
x.height = -5 # raises ValueError
h = Head()
x.head = h # raises AttributeError, IIRC

Share this post


Link to post
Share on other sites
Fixed: properties silently fail on classic classes. Your classes must be derived from object, like so:


class Head(object):
def __get_nose(self):
return self.__nose

def __set_nose(self, value):
if value < 0:
raise ValueError("A Head can not have a negatively sized nose!")
self.__nose = value

def __init__(self):
self.__nose = 4

nose = property(__get_nose, __set_nose) # nose can not be deleted


class Human(object):
def __get_head(self):
return self.__head

def __set_head(self, value):
raise AttributeError("A Human Head can not be replaced!")

def __get_height(self):
return self.__height

def __set_height(self, value):
if value < 0:
raise ValueError("A Human can not have a negative height!")
self.__height = value

def __init__(self):
self.__height = 4
self.__head = Head()

head = property(__get_head, __set_head) # head can not be set or deleted
height = property(__get_height, __set_height)


Hope that helped someone!

Share this post


Link to post
Share on other sites
Quote:
Original post by mikeman
Right now, "nose","head" and "height" are class attributes. They belong to the classes HEAD and HUMAN respectively, not to instances of those classes(objects). When you do "y.head" or "x.head", you actually access the class attribute "HUMAN.head" both times. What you actually need is data attributes:

*** Source Snippet Removed ***


mucho gracis for the reply, but "x.height" and "y.height" are still independtly variable, unlike x.head.nose and y.head.nose. are you sure they're all class attribuites?

Share this post


Link to post
Share on other sites
Quote:
Original post by seanmusgrave
mucho gracis for the reply, but "x.height" and "y.height" are still independtly variable, unlike x.head.nose and y.head.nose. are you sure they're all class attribuites?

Numbers are immutable in Python, so x.height and y.height are the same instance initially, but become different instances when y.height is replaced.

Share this post


Link to post
Share on other sites
Quote:
Original post by seanmusgrave
Quote:
Original post by mikeman
Right now, "nose","head" and "height" are class attributes. They belong to the classes HEAD and HUMAN respectively, not to instances of those classes(objects). When you do "y.head" or "x.head", you actually access the class attribute "HUMAN.head" both times. What you actually need is data attributes:

*** Source Snippet Removed ***


mucho gracis for the reply, but "x.height" and "y.height" are still independtly variable, unlike x.head.nose and y.head.nose. are you sure they're all class attribuites?


Yes, they're all class attributes. The thing is, when you do "x.height=42", it doesn't set the class attribute "height" to 42, it sets/creates a data attribute "height" for instance "x". Remember that in Python you can add new attributes on the fly. Try this:


class Foo:
x=1

a=Foo()
b=Foo()

print a.x,b.x
print "a:",a.__dict__,"b:",b.__dict__
print "Foo:",Foo.__dict__

a.x=42
print a.x,b.x
print "a:",a.__dict__,"b:",b.__dict__
print "Foo:",Foo.__dict__







You'll see that, after "a.x=42", the class attribute "x" is the same, but instance "a" has a new attribute x:42, which "overshadows" the class attribute with the same name, because it is looked up first.

OTOH, the command "x.head.nose" first retrieves the attribute "x.head"(which is a class attribute), and then sets the attribute "nose". So it works as expected.

Generally, try to remember that classes are little more than dictionaries. If "foo" is an instance of Foo, then the following rules apply:

(1)Extracting an attribute "x": "print foo.x" or "foo.x.y=42"(remember:this doesn't write to the "x" attribute, it reads the "x" attribute and writes to the "y" attribute of the retrieved object).

First, "x" is looked up in the instance's dictionary(data attribute). If it's not there, it's looked up in the class' dictionary(class attribute). If it's still not there, an error occurs.

(2)Setting an attribute "x": foo.x=42
An entry in the instance's dictionary is created(if it doesn't already exists), and it's set to reference the object "42".

So you see, you can read class attributes through instances, but you cannot set them. If you want to alter a class attribute, you have to do Foo.x=42 directy.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement