Can python objects have nested properties?
Asked Answered
H

2

12

I have an object defined as follows

class a():
    @property
    def prop(self):
        print("hello from object.prop")
        @property
        def prop1(self):
            print("Hello from object.prop.prop")

When I call

>>> obj = a()
>>> obj.prop
hello from object.prop
>>> obj.prop.prop

I get the following traceback error

Traceback (most recent call last):
  File "object_property.py", line 13, in <module>
    a.prop.prop1
AttributeError: 'NoneType' object has no attribute 'prop1'

What I am trying to figure out is if I can define nested properties for objects?

Harrold answered 29/7, 2013 at 1:23 Comment(2)
The property would have to return the second property. Simply declaring the second property within the first doesn't make it an attribute.Bidle
@ValekHalfHeart: Returning a property object won't work. You need to return an instance of a class that contains a property object.Steiermark
I
12

The traceback is because your property doesn't have a return statement, hence it returns NoneType, which obviously can't have attributes of its own. Your property would probably need to return an instance of a different class, that has its own prop attribute. Something like this:

class a():
    def __init__(self):
        self.b = b()
    @property
    def prop(self):
        print("hello from object.prop")
        return self.b

class b():
    @property
    def prop(self):
        print("Hello from object.prop.prop")

x = a()
print x.prop.prop
>> hello from object.prop
>> Hello from object.prop.prop
>> None
Impignorate answered 29/7, 2013 at 1:34 Comment(2)
this is not the "nested property" asked in the questionHousekeeping
@hago, I think it is actually. As it does achieve the goal trying to be achieved in the question. It also works for me, where I had a similar question as the orginal poster.Linea
S
4

In general, no, there's no way to wrap up the attribute access of an object other than yourself. Certainly there's nothing with a syntax that can be nested neatly (you can declare a class within your property function, but it gets ugly fast).

That is, in an expression like obj.prop_a.prop_b, the top level object obj can't directly control what happens with the prop_b attribute access, which is happening on a different object.

As an example, consider the following sequence of statements:

foo = obj.prop_a
bar = foo.prop_b

The value assigned to bar is the same as obj.prop_a.prop_b, but that statement didn't directly refer to obj at all.

If you're willing to get into the murky world of wrapper objects, it might be possible to do what you want, but it's not going to be as neat as a basic property. Like in @qwwqwwq's answer, you can have obj.prop_a return an an instance of a class with its own @property decorated function prop_b.

You could even declare the class inside of the prop_a function, if you weren't worried about it being accessible from the outside world. For anything complicated though, it will get messy fast.

Instead, consider if what you want to be accessible through obj.prop_a.prop_b could be better exposed through a property or method directly on obj, such as obj.prop_a_b. I suspect you'll find a much better design this way.

Steiermark answered 29/7, 2013 at 3:21 Comment(1)
do you think that Style attribute and its properties could have been designed better without such tricks in ipywidgets?Cornellcornelle

© 2022 - 2024 — McMap. All rights reserved.