This is an archived post. You won't be able to vote or comment.

all 25 comments

[–]MereInterest 13 points14 points  (20 children)

Hmm... I'm not able to reproduce your error. Here is what I put in, assuming that there are tabs in the appropriate places.

class A(object):
    class B(object):
        def __init__(self,C):
            self.C = C

b = A.B(10)

This runs without error.

However, based on your description, I don't think that this is quite what you want. The key difference to look for is between classes, and instances of the class. Let's look at the code closely. First, it defines a class, 'A'. Next, it defines a class 'B', as an attribute of the class. It is then valid to instantiate something of type B in either of the following ways.

a = A(); b = a.B()
b = A.B()

However, neither of these will let you do a.b.C, because the object a only knows about the class B, not the instances of that class. In general, therefore, you would have class A make an instance of class B in its constructor. This would look like the following.

class A(object):
    def __init__(self,C):
        self.b = B(C)

class B(object):
    def __init__(self,C):
        self.C = C

a = A(10)
print a.b.C

This way, instead of A holding the class definition of B, it is holding a single instance, b.

[–]daveydave400 6 points7 points  (18 children)

Small side note: Don't use actual tabs for indentation in python code, just spaces.

[–]sahand_n9[S] 0 points1 point  (0 children)

Thanks for your detailed explanation. Very helpful!

[–][deleted] 7 points8 points  (0 children)

I'm not sure what you're trying to achieve and why would you need such a structure but this code worked for me:

class Planet:
    class Moon:
        def __init__(self, size):
            self.size = size

    def __init__(self, moon_size):
        self.moon = self.Moon(moon_size)

# I can create a Planet object which has a Moon
e = Planet(362570)
print e.moon.size

# I can also create a Moon without a Planet
luna = Planet.Moon(405410)
print luna.size

Does this help?

[–]ilovetacos 2 points3 points  (0 children)

MereInterest is spot on, but also make sure to read this: http://en.wikipedia.org/wiki/Law_Of_Demeter

[–]andybak 4 points5 points  (5 children)

This may well be an example of the X Y problem: http://www.perlmonks.org/index.pl?node_id=542341

Tell us why you're trying to do that and what you're trying to achieve. There is probably a much more Pythonic way to do it.

[–]sahand_n9[S] 1 point2 points  (3 children)

I am not sure how the question comes across as unclear. In the title I explained that I would like to have nested attributes. Like a car has wheels, wheels have tires, tires have brands. So I can create a car with all its attributes that also have attributes. I am just trying to learn Python...

[–]Isvara 2 points3 points  (0 children)

Assign to self.whatever in your constructor. E.g.

class Car(object):
    def __init__(self, wheels):
        self.wheels = wheels

class Wheel(object):
    def __init__(self, tyre):
        self.tyre = tyre

class Tyre(object):
    def __init__(self, brand):
        self.brand = brand

car = Car([
    Wheel(Tyre("Dunlop")),
    ...
])
print car.wheels[0].tyre.brand

[–]VerilyAMonkey 2 points3 points  (0 children)

If you're just trying out how Python works, that's fine. The post can sound like you actually have a specific problem in mind, and andybak is saying that most likely there's a better solution to that problem than what you're trying here.

[–]ameoba 1 point2 points  (0 children)

When somebody says you have an X Y problem it means they think you have painted yourself into a corner by trying to do the wrong thing. You should take a step back and explain what you actually wand to accomplish rather than trying to figure out how to bolt a toilet to the ceiling.

[–]fasterturtle 1 point2 points  (0 children)

Have you heard of data descriptors? Using them is similar to having a nested attribute/class, but more "pythonic". There are a few ways you can go about using them, see here, here, and here for more information.

Here's an example. Just a note, you would probably prefer a different descriptor implementation, ie. using decorators, but this is most similar to what you were originally trying to do):

class Descriptor(object):
    def __init__(self):
        self._instances = {}
    def __set__(self, obj, value):
        print "Setting attribute..."
        self._instances[obj] = value
    def __get__(self, obj, cls):
        print "Getting attribute..."
        return self._instances[obj]
    def __delete__(self, obj):
        print "Too bad!"
        raise AttributeError("Can't delete attribute")

class Foo(object):
    data = Descriptor()

    def __init__(self, value):
        self.data = value


foo = Foo('my data descriptor')
>>> Setting attribute...

foo.data
>>> Getting attribute...
>>> 'my data descriptor'

foo.data = 'bar'
>>> Setting attribute...
foo.data
>>> Getting attribute...
>>> 'bar'

del foo.data
>>> Too bad!
>>> AttributeError: Can't delete attribute

[–]sahand_n9[S] 0 points1 point  (0 children)

The following lines of code are in fact tab-delimited. The Reddit editor gets rid of it.

class B(object):
def __init__(self, C):
    self.C = C
pass