views:

195

answers:

3

I have a code snippet like this

class A(object):
    class b:
        def print_hello(self):
            print "Hello world"
    b = property(b)

And I want to override the inner class b (please dont worry about the lowercase name) behaviour. Say, I want to add a new method or I want to change an existing method, like:

class C(A):
    class b(A.b):
        def print_hello(self):
            print "Inner Class: Hello world"
    b = property(b)

Now if I create C's object as c = C(), and call c.b I get TypeError: 'property' object is not callable error. How would I get pass this and call print_hello of the extended inner class? Disclaimer: I dont want to change the code for A class.

Update: The base class 'A' tries to simulate a class which I have seen in one of the opensource apis. So thats why I dont want to change the core api, but extend it for my own requirement.

+1  A: 

I'm not really sure why you would define the inner class as a property of the outer class. (I'm no Python expert, so perhaps there's a reason I'm not aware of).

It seems to work fine without the properties:

class A(object):
    class b:
        def print_hello(self):
            print "A Hello world"

class C(A):
    class b(A.b):
        def print_hello(self):
            print "C Hello world"


outer = C()
inner = outer.b()
inner.print_hello() # prints "C Hello world"
Evgeny
A: 

Whenever you access an A's 'b' property, a reference to the A instance is passed to the getter - which is then passed as an argument to b's constructor. That breaks your construction right from the start, because b's (default) constructor doesn't take any extra arguments.

It looks like your C class doesn't work because it's inner 'b' class inherits from A's 'b' property object.

I'm curious as to why you would want a property here - it does nothing but complicating things. In fact, removing it would allow you to replace A's inner 'b' class with another class on a per-instance base, without having to resort to inheritance at all. Can you give us some more information to work with, e.g. the intentions and purpose behind this construction?

Pieter Witvoet
A: 

The reason why this fails is that due to the b = property(b) line A.b is not the class you defined, but a property object. I'm actually a bit surprised that it doesn't fail on class creation. It would work if you used A.b.fget as the base class. But the correct answer would be: don't do that. Python doesn't have inner classes in any regular sense, a class defined in class definition scope is no different from a regular class. In fact this code has the exact same end result:

class A(object):
    pass

class b(object):
    def print_hello(self):
        print("Hello world")

A.b = property(b)

I'm not sure what exactly it is that you are trying to achieve. If I understand correctly you have a parent class that has a property that returns instances of another class and you want to have a subclass that has a property that returns instances of a subclass of the other class. To subclass the returned class you need to get a reference to that class to use it as the base. Then you can just override the property to return instances of your subclass. If you use a property that looks up the class from the instance you actually don't need to override the property definition:

class A(object):
    class B(object):
        def print_hello(self):
            print("Hello from A.B")
    b = property(lambda self: self.B())

class C(A):
    class B(A.B):
       def print_hello(self):
           print("Hello from C.B")

A().b.print_hello()
C().b.print_hello()
Ants Aasma