sri sri - 3 months ago 11
Python Question

In nested classes, how to access outer class's elements from nested class in Python?

I have this scenario, where I need to ask a nested class to append items to a list in the outer class. Heres pseudocode thats similar to what Im trying to do. How would I go about getting it to work?

class Outer(object):
outerlist = []
class Inner(object):
def __call__(self, arg1):
outerlist.append(arg1)

if __name__ == "__main__":
f = Outer()
f.Inner("apple")
f.Inner("orange")

print f.outerlist()


This is what I hope to see -
apple, orange


Details:

OS X, Python 2.7

Answer

Now that I understand your design, you're going about things all wrong.

First, Outer is a class; it doesn't get __call__ed. Your line 17 is just going to construct an empty Outer object and do nothing with it. If you want to "call" the Outer object, you can define an __init__ method—or, as Sheena suggests, define a __new__ and intercept the initialization, since you don't actually need the initialized object anyway.

Honestly, I don't think someone who doesn't understand how __call__ works yet should be trying to build something tricky like this yet. But if you insist, read on.

It's a very odd, and probably bad, design to collect this kind of stuff in a class instead of an instance. Keep in mind that class variables are effectively globals, with all that entails. If you try to use Outer reentrantly, or from multiple threads/event handlers/greenlets/whatever, the uses will end up stomping all over each other. Even if you think that isn't possibly going to be a problem now, it likely will at some point in the future.

You could create an Outer instance, and use its members as decorators. For example:

from outer_library import Outer

outer = Outer()

@outer.get("/")
…

But I'm not sure that's much better. The entire design here seems to involve performing actions at the module level, even though it looks like you're just defining normal functions and calling a function at the end. The fact that you've managed to confuse yourself should be evidence of how confusing a design this is.

But if you do want to do that, what you probably want to do is define classes inside the Outer.__init__ method, and assign them to instance members. Classes are first-class values, and can be assigned to variables just like any other values. Then, use the __init__ (or __new__) methods of those classes to do the work you wanted, making the classes simulate functions.

This may seem confusing or misleading. But remember that the whole point of what you're trying to do is to use a class in a way that it looks like a method, so that kind of confusion is inherent in the problem. But if you prefer, you can write decorators as functions (in this case, as normal instance methods of Outer); it just makes a different part of the problem harder instead of this part.

A more normal way to design something like this would be to make Outer a perfectly normal class that people can either subclass or create instances of, and provide an explicit non-fancy way to attach handler methods or functions to URLs. Then, once that's working, design a way to simplify that handler registration with a decorator.

Comments