Python's inner/nested classes confuse me. Is there something that can't be accomplished without them? If so, what is that thing?
9 Answers
Quoted from http://www.geekinterview.com/question_details/64739:
Advantages of inner class:
- Logical grouping of classes: If a class is useful to only one other class then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.
- Increased encapsulation: Consider two top-level classes A and B where B needs access to members of A that would otherwise be declared private. By hiding class B within class A A's members can be declared private and B can access them. In addition B itself can be hidden from the outside world.
- More readable, maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.
The main advantage is organization. Anything that can be accomplished with inner classes can be accomplished without them.

- 20,065
- 8
- 63
- 69
-
59The encapsulation argument of course does not apply to Python. – bobince Apr 06 '09 at 16:23
-
38The first point doesn't apply to Python either. You can define as many classes in one module file as you like, thus keeping them together and the package organization is not affected either. The last point is very subjective and I don't believe it's valid. In short, I don't find any arguments supporting the use of inner classes in Python in this answer. – Chris Arndt Jan 22 '12 at 20:15
-
20Nevertheless, these ARE the reasons that inner classes are used in programming. You're just trying to shoot down a competing answer. This answer this dude gave here is solid. – Inversus Apr 10 '14 at 13:06
-
21@Inversus: I disagree. This is not an answer, it is an extended quotation from someone else's answer *about a different language* (namely Java). Downvoted and I hope others do the same. – Kevin Feb 12 '16 at 04:20
-
5Of course Python has encapsulation -- it just relies on courtesy rather than language level enforceable. See the discussion of "non-public" information in [PEP8](https://www.python.org/dev/peps/pep-0008/) – gerardw Mar 07 '17 at 22:14
-
8I agree with this answer and disagree with the objections. While nested classes _are not_ Java's inner classes, they are useful. The purpose of a nested class is organization. Effectively, you are putting one class under the namespace of another. When it makes logical sense to do so, this _is_ Pythonic: "Namespaces are one honking great idea -- let's do more of those!". For example, consider a `DataLoader` class that can throw a `CacheMiss` exception. Nesting the exception under the main class as `DataLoader.CacheMiss` means you can import just `DataLoader` but still use the exception. – cbarrick Oct 01 '17 at 04:05
-
7@ChrisArndt why contaminate the entire module namespace with what is clearly a class def that only makes sense as a child of another class? – cowbert Oct 25 '17 at 22:55
-
3@cbarrick the Encapsulation portion of the answer is clearly wrong for Python though. First, the child class (B) has no access to the parent (A) class's members unless B's `__init__` takes an instance of A as an argument, and secondly, "private" encapsulation does not apply to Python (you can always call B from outside of A even if the call is nontrivial). – cowbert Oct 25 '17 at 23:04
-
Doing "more of those [namespaces]" says nothing about nesting them. – Ethan Furman Sep 11 '18 at 17:05
-
2If a module already has a little too many classes in one file, then you can group those closely related classes under one sub-roof, either you put them into separated modules, or you can take advantage of inner class. It is just one mechanism provided by Python to you. To use or not really depends on your situation and taste. – HZhang Sep 14 '18 at 22:21
-
all i'll say is that the tags say python and advantages of inner classes should be given within that language – Jan 22 '20 at 17:16
-
downvoted because the encapsulation argument does not apply to python, and this specific question is about python only – R71 Apr 09 '20 at 11:31
-
1Some of the criticism here is pretty weak. There's a lot of talk about "that's not how it works in this language," when what's being discussed is a computer science concept (which is inherently an abstract thing). This falls into the category of programming in a language vs programming into a language. This is a programming concept, plain and simple. The question is about how a specific language (Python) facilitates a CS mechanism (and implicitly how strongly or weakly if supports that facilitation). 100% valid answer – acat Jun 07 '21 at 04:18
Is there something that can't be accomplished without them?
No. They are absolutely equivalent to defining the class normally at top level, and then copying a reference to it into the outer class.
I don't think there's any special reason nested classes are ‘allowed’, other than it makes no particular sense to explicitly ‘disallow’ them either.
If you're looking for a class that exists within the lifecycle of the outer/owner object, and always has a reference to an instance of the outer class — inner classes as Java does it – then Python's nested classes are not that thing. But you can hack up something like that thing:
import weakref, new
class innerclass(object):
"""Descriptor for making inner classes.
Adds a property 'owner' to the inner class, pointing to the outer
owner instance.
"""
# Use a weakref dict to memoise previous results so that
# instance.Inner() always returns the same inner classobj.
#
def __init__(self, inner):
self.inner= inner
self.instances= weakref.WeakKeyDictionary()
# Not thread-safe - consider adding a lock.
#
def __get__(self, instance, _):
if instance is None:
return self.inner
if instance not in self.instances:
self.instances[instance]= new.classobj(
self.inner.__name__, (self.inner,), {'owner': instance}
)
return self.instances[instance]
# Using an inner class
#
class Outer(object):
@innerclass
class Inner(object):
def __repr__(self):
return '<%s.%s inner object of %r>' % (
self.owner.__class__.__name__,
self.__class__.__name__,
self.owner
)
>>> o1= Outer()
>>> o2= Outer()
>>> i1= o1.Inner()
>>> i1
<Outer.Inner inner object of <__main__.Outer object at 0x7fb2cd62de90>>
>>> isinstance(i1, Outer.Inner)
True
>>> isinstance(i1, o1.Inner)
True
>>> isinstance(i1, o2.Inner)
False
(This uses class decorators, which are new in Python 2.6 and 3.0. Otherwise you'd have to say “Inner= innerclass(Inner)” after the class definition.)

- 528,062
- 107
- 651
- 834
-
6The use-cases that call for *that* (i.e. Java-esque inner classes, whose instances have a relationship with instances of the outer class) can typically be addressed in Python by defining the inner class inside *methods* of the outer class — they will see the outer's `self` without any extra work required (just use a different identifier where you would typically put the inner's `self`; like `innerself`), and will be able to access the outer instance via that. – Evgeni Sergeev Apr 19 '16 at 04:27
-
Using a `WeakKeyDictionary` in this example doesn't actually allow the keys to be garbage collected, because the values strongly reference their respective keys through their `owner` attribute. – Kritzefitz Apr 15 '19 at 15:13
There's something you need to wrap your head around to be able to understand this. In most languages, class definitions are directives to the compiler. That is, the class is created before the program is ever run. In python, all statements are executable. That means that this statement:
class foo(object):
pass
is a statement that is executed at runtime just like this one:
x = y + z
This means that not only can you create classes within other classes, you can create classes anywhere you want to. Consider this code:
def foo():
class bar(object):
...
z = bar()
Thus, the idea of an "inner class" isn't really a language construct; it's a programmer construct. Guido has a very good summary of how this came about here. But essentially, the basic idea is this simplifies the language's grammar.

- 192,085
- 135
- 376
- 510
Nesting classes within classes:
Nested classes bloat the class definition making it harder to see whats going on.
Nested classes can create coupling that would make testing more difficult.
In Python you can put more than one class in a file/module, unlike Java, so the class still remains close to top level class and could even have the class name prefixed with an "_" to help signify that others shouldn't be using it.
The place where nested classes can prove useful is within functions
def some_func(a, b, c):
class SomeClass(a):
def some_method(self):
return b
SomeClass.__doc__ = c
return SomeClass
The class captures the values from the function allowing you to dynamically create a class like template metaprogramming in C++

- 449
- 2
- 6
- 9
Is there something that can't be accomplished without them? If so, what is that thing?
There is something that cannot be easily done without: inheritance of related classes.
Here is a minimalist example with the related classes A
and B
:
class A(object):
class B(object):
def __init__(self, parent):
self.parent = parent
def make_B(self):
return self.B(self)
class AA(A): # Inheritance
class B(A.B): # Inheritance, same class name
pass
This code leads to a quite reasonable and predictable behaviour:
>>> type(A().make_B())
<class '__main__.A.B'>
>>> type(A().make_B().parent)
<class '__main__.A'>
>>> type(AA().make_B())
<class '__main__.AA.B'>
>>> type(AA().make_B().parent)
<class '__main__.AA'>
If B
were a top-level class, you could not write self.B()
in the method make_B
but would simply write B()
, and thus lose the dynamic binding to the adequate classes.
Note that in this construction, you should never refer to class A
in the body of class B
. This is the motivation for introducing the parent
attribute in class B
.
Of course, this dynamic binding can be recreated without inner class at the cost of a tedious and error-prone instrumentation of the classes.

- 1
- 1
- 5
-
You can trivially write `B = B` in the body of `A`; the ability or inability to nest a class definition in another has little to do with having class-valued attributes. – chepner Aug 31 '22 at 22:20
I understand the arguments against nested classes, but there is a case for using them in some occasions. Imagine I'm creating a doubly-linked list class, and I need to create a node class for maintaing the nodes. I have two choices, create Node class inside the DoublyLinkedList class, or create the Node class outside the DoublyLinkedList class. I prefer the first choice in this case, because the Node class is only meaningful inside the DoublyLinkedList class. While there's no hiding/encapsulation benefit, there is a grouping benefit of being able to say the Node class is part of the DoublyLinkedList class.

- 703
- 8
- 10
-
5This is true assuming the same `Node` class is not useful for other types of linked list classes that you might also create, in which case it should probably just be outside. – Asclepius Apr 07 '14 at 19:34
-
Another way to put it: `Node` is under the namespace of `DoublyLinkedList`, and it makes logical sense to be so. This _is_ Pythonic: "Namespaces are one honking great idea -- let's do more of those!" – cbarrick Oct 01 '17 at 03:59
-
2@cbarrick: Doing "more of those" says nothing about nesting them. – Ethan Furman Sep 11 '18 at 17:04
1. Two functionally equivalent ways
The two ways shown before are functionally identical. However, there are some subtle differences, and there are situations when you would like to choose one over another.
Way 1: Nested class definition
(="Nested class")
class MyOuter1:
class Inner:
def show(self, msg):
print(msg)
Way 2: With module level Inner class attached to Outer class
(="Referenced inner class")
class _InnerClass:
def show(self, msg):
print(msg)
class MyOuter2:
Inner = _InnerClass
Underscore is used to follow PEP8 "internal interfaces (packages, modules, classes, functions, attributes or other names) should -- be prefixed with a single leading underscore."
2. Similarities
Below code snippet demonstrates the functional similarities of the "Nested class" vs "Referenced inner class"; They would behave the same way in code checking for the type of an inner class instance. Needless to say, the m.inner.anymethod()
would behave similarly with m1
and m2
m1 = MyOuter1()
m2 = MyOuter2()
innercls1 = getattr(m1, 'Inner', None)
innercls2 = getattr(m2, 'Inner', None)
isinstance(innercls1(), MyOuter1.Inner)
# True
isinstance(innercls2(), MyOuter2.Inner)
# True
type(innercls1()) == mypackage.outer1.MyOuter1.Inner
# True (when part of mypackage)
type(innercls2()) == mypackage.outer2.MyOuter2.Inner
# True (when part of mypackage)
3. Differences
The differences of "Nested class" and "Referenced inner class" are listed below. They are not big, but sometimes you would like to choose one or the other based on these.
3.1 Code Encapsulation
With "Nested classes" it is possible to encapsulate code better than with "Referenced inner class". A class in the module namespace is a global variable. The purpose of nested classes is to reduce clutter in the module and put the inner class inside the outer class.
While no-one* is using from packagename import *
, low amount of module level variables can be nice for example when using an IDE with code completion / intellisense.
*Right?
3.2 Readability of code
Django documentation instructs to use inner class Meta for model metadata. It is a bit more clearer* to instruct the framework users to write a class Foo(models.Model)
with inner class Meta
;
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
instead of "write a class _Meta
, then write a class Foo(models.Model)
with Meta = _Meta
";
class _Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
class Ox(models.Model):
Meta = _Meta
horn_length = models.IntegerField()
With the "Nested class" approach the code can be read a nested bullet point list, but with the "Referenced inner class" method one has to scroll back up to see the definition of
_Meta
to see its "child items" (attributes).The "Referenced inner class" method can be more readable if your code nesting level grows or the rows are long for some other reason.
* Of course, a matter of taste
3.3 Slightly different error messages
This is not a big deal, but just for completeness: When accessing non-existent attribute for the inner class, we see slighly different exceptions. Continuing the example given in Section 2:
innercls1.foo()
# AttributeError: type object 'Inner' has no attribute 'foo'
innercls2.foo()
# AttributeError: type object '_InnerClass' has no attribute 'foo'
This is because the type
s of the inner classes are
type(innercls1())
#mypackage.outer1.MyOuter1.Inner
type(innercls2())
#mypackage.outer2._InnerClass

- 28,336
- 10
- 93
- 96
The main use case I use this for is the prevent proliferation of small modules and to prevent namespace pollution when separate modules are not needed. If I am extending an existing class, but that existing class must reference another subclass that should always be coupled to it. For example, I may have a utils.py
module that has many helper classes in it, that aren't necessarily coupled together, but I want to reinforce coupling for some of those helper classes. For example, when I implement https://stackoverflow.com/a/8274307/2718295
:utils.py
:
import json, decimal
class Helper1(object):
pass
class Helper2(object):
pass
# Here is the notorious JSONEncoder extension to serialize Decimals to JSON floats
class DecimalJSONEncoder(json.JSONEncoder):
class _repr_decimal(float): # Because float.__repr__ cannot be monkey patched
def __init__(self, obj):
self._obj = obj
def __repr__(self):
return '{:f}'.format(self._obj)
def default(self, obj): # override JSONEncoder.default
if isinstance(obj, decimal.Decimal):
return self._repr_decimal(obj)
# else
super(self.__class__, self).default(obj)
# could also have inherited from object and used return json.JSONEncoder.default(self, obj)
Then we can:
>>> from utils import DecimalJSONEncoder
>>> import json, decimal
>>> json.dumps({'key1': decimal.Decimal('1.12345678901234'),
... 'key2':'strKey2Value'}, cls=DecimalJSONEncoder)
{"key2": "key2_value", "key_1": 1.12345678901234}
Of course, we could have eschewed inheriting json.JSONEnocder
altogether and just override default():
:
import decimal, json
class Helper1(object):
pass
def json_encoder_decimal(obj):
class _repr_decimal(float):
...
if isinstance(obj, decimal.Decimal):
return _repr_decimal(obj)
return json.JSONEncoder(obj)
>>> json.dumps({'key1': decimal.Decimal('1.12345678901234')}, default=json_decimal_encoder)
'{"key1": 1.12345678901234}'
But sometimes just for convention, you want utils
to be composed of classes for extensibility.
Here's another use-case: I want a factory for mutables in my OuterClass without having to invoke copy
:
class OuterClass(object):
class DTemplate(dict):
def __init__(self):
self.update({'key1': [1,2,3],
'key2': {'subkey': [4,5,6]})
def __init__(self):
self.outerclass_dict = {
'outerkey1': self.DTemplate(),
'outerkey2': self.DTemplate()}
obj = OuterClass()
obj.outerclass_dict['outerkey1']['key2']['subkey'].append(4)
assert obj.outerclass_dict['outerkey2']['key2']['subkey'] == [4,5,6]
I prefer this pattern over the @staticmethod
decorator you would otherwise use for a factory function.

- 3,212
- 2
- 25
- 34
I have used Python's inner classes to create deliberately buggy subclasses within unittest functions (i.e. inside def test_something():
) in order to get closer to 100% test coverage (e.g. testing very rarely triggered logging statements by overriding some methods).
In retrospect it's similar to Ed's answer https://stackoverflow.com/a/722036/1101109
Such inner classes should go out of scope and be ready for garbage collection once all references to them have been removed. For instance, take the following inner.py
file:
class A(object):
pass
def scope():
class Buggy(A):
"""Do tests or something"""
assert isinstance(Buggy(), A)
I get the following curious results under OSX Python 2.7.6:
>>> from inner import A, scope
>>> A.__subclasses__()
[]
>>> scope()
>>> A.__subclasses__()
[<class 'inner.Buggy'>]
>>> del A, scope
>>> from inner import A
>>> A.__subclasses__()
[<class 'inner.Buggy'>]
>>> del A
>>> import gc
>>> gc.collect()
0
>>> gc.collect() # Yes I needed to call the gc twice, seems reproducible
3
>>> from inner import A
>>> A.__subclasses__()
[]
Hint - Don't go on and try doing this with Django models, which seemed to keep other (cached?) references to my buggy classes.
So in general, I wouldn't recommend using inner classes for this kind of purpose unless you really do value that 100% test coverage and can't use other methods. Though I think it's nice to be aware that if you use the __subclasses__()
, that it can sometimes get polluted by inner classes. Either way if you followed this far, I think we're pretty deep into Python at this point, private dunderscores and all.
-
3
-
In the Above casse Buggy inherits from A. So __sublass__ shows that. Also see built-in function [issubclass()](https://docs.python.org/3/library/functions.html#issubclass) – klaas Dec 15 '15 at 15:28
-
Thanks @klaas, I think it could be made clearer that I'm just using `.__subclasses__()` to understand how inner classes interact with the garbage collector when things go out of scope in Python. That does visually seem to dominate the post so the first 1-3 paragraphs deserve a bit more expansion. – pzrq Dec 17 '15 at 12:41