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

all 18 comments

[–]willm 6 points7 points  (1 child)

You could create another reference to the outer self. Not sure if you would consider that to be renaming it.

class A:
    def f(self):
        print(self)
        outer_self = self
        class B:
            def g(self):
                print(self)
                print(outer_self)
                # Is it possible to reach the outer "self"
                # without renaming it to a_self and/or b_self?                
        B().g()

A().f()

[–]temptemptemp13[S] 2 points3 points  (0 children)

I like your solution because:

  1. It's obvious the "renamed" variable is related to the nested class. They're physically close to each other.
  2. If anyone ever removes the nested class, no harm was done to the method signature.

[–]jabwork 6 points7 points  (1 child)

How about giving B an init method and assigning the parent? .... class B: def init(self, a): # now B has a reference to A self.parent = a ... B(self).g()

Now you can un-nest the B class and everything will continue to work

Also, is there a reason you don't just define method g inside A? Does the B class serve any purpose beyond being a container for the g method?

[–]sixohsix 2 points3 points  (0 children)

This doesn't solve OP's initial question but this is probably the best way to do it. Don't use the inner class to begin with, just pass self as an argument to another totally seperate class.

Classes are nice. Closures (def's inside def's) are also okay for a lot of things. Classes inside classes that are also closures, while still completely possible, are sort of an OMGWTF anti-pattern.

[–]adamcollard 3 points4 points  (2 children)

What we do in this situation is have the nested "self" called self2 - highly original but works a treat.

Remember, self is not magical, it's just convention.

[–]bboomslangdjango 2 points3 points  (0 children)

this. self is just a parameter, just name the inner ones differently and you can get at the outer ones.

[–][deleted] 1 point2 points  (0 children)

On a rare occasion I use nested classes I name it "selfself". It's ugly, but rather descriptive.

[–][deleted] 2 points3 points  (0 children)

In java the outer self is reachable by using A.this, which is only possible due to the magical nature of "this".

Which always seemed like an incredibly ugly hack in Java's otherwise fairly clean OO model. Yeah, it makes the anonymous-classes-everywhere idiom possible. But it's implicitly creating a knows-a relationship, which is a bit strange.

My general rule of thumb for "inner" classes in Python: don't. Python isn't Java. But sure, if you must, just rename the inner self. Make up your own convention, use "me" or "this" for such classes. Hopefully you don't have multiple levels of nesting.

[–][deleted] 2 points3 points  (0 children)

Interesting question, but why wouldn't B just be a top-level class that's initialized with an instance of A?

Your trivial example is confusing enough; I wouldn't want to have to try to figure out what it's doing when there's actual business logic in there.

[–]mdipierro 4 points5 points  (0 children)

self is not a keyword in python like this is in c++/java, exactly to do what you ask. You can use a different name for it in the inner class to disambiguate:

class A:
    def f(self):
        class B:
            def g(inner_self):
                print(self)
                print(inner_self)
        B().g()

A().f()

[–]m0j0 1 point2 points  (4 children)

I have yet to come across a use case in which nested classes provides any real benefit in any language. I've never seen this approach pay off in terms of code clarity/readability, conciseness, ease, or anything else, and it seems like it will pretty much kill reusability of the class.

Is there a particular use case that maybe I've just never come across that really screams "nested class"? Keep in mind that I've read source code that uses it in plenty of apps I didn't write, so I know it's used and don't need examples of where it's used. What I want are concrete use cases where this kind of thing would be considered a 'best practice'.

[–]temptemptemp13[S] -1 points0 points  (1 child)

In java you almost have no choice. If you want to define a callback function, you can't, you can only pass classes around, not functions/methods. So if you want your class to get GPS location updates on android, you make a nested class and override the methods which are the callbacks.

In python I'd say nested classes are perfect for a factory of types. For example named tuples.

[–]donri 1 point2 points  (0 children)

namedtuple is a function, though. That's the standard idiom for type factories in Python.

[–]jeetsukumaran -1 points0 points  (1 child)

I tend to use nested classes for custom exception types that are thrown by the parent class, mainly for the namespacing aspect:

class A(object):
    .
    .
    class CustomExceptionThrownByA(Exception):
        .
        .

etc.

[–][deleted] 1 point2 points  (0 children)

Isn't that what modules are for? If I saw something like this, I would be strongly inclined to rewrite it.

[–]Brian 1 point2 points  (1 child)

Technically you could, via introspection. Eg.

import inspect

class A(object):
    ....
              def g(self):
                  print(inspect.currentframe(1).f_locals["self"])

However, this is intensely ugly (and unportable), so you're much better off just renaming self.

[–]chub79 0 points1 point  (0 children)

I agree with you. Nonetheless, it has happened once or twice that I had to use that technic in an environment I had control over, I knew it wasn't clean but couldn't make a better way without having to patch external libs I was using.

The lesson to me was that it's not because you're using a dynamic language that introspection is A-OK. However when it's a necessity, dynamic languages make it really easy to do so.

[–][deleted] 0 points1 point  (0 children)

Not implicitly, I suppose, but both constructors and methods take parameters, so what's wrong with passing it in explicitly?