Reputation: 7888
I like to use the structures built into the language to organize my code. But there is one situation where I can't stay consistent, simply because I don't see a definitive best way of doing it. It's regarding support classes, that is, classes that are exclusively used internally by another class: Do I make them inner classes, or separate classes.
Inner classes:
class Complicated:
class Utility1:
pass
class Utility2:
pass
pass
Separate classes:
class Complicated:
pass
class Utility1:
pass
class Utility2:
pass
Inner classes has the advantage of being scoped inside the only class that uses them. But the problem is that I get less space to write code due to indentation.
Outer classes have neither the advantage nor the disadvantage. I am tired of always spending some mental energy whenever I write support classes, wondering about this silly issue.
My question is whether anyone with a substantial python experience on their back can advise as to whether there is a best practice regarding this? Even if the answer is that "it depends", it is appreciated if it comes with someone more experienced than myself.
Upvotes: 3
Views: 1680
Reputation: 181
Python inner classes are possible to create and use. Unlike other languages, such as Java, Python inner classes don't automatically give you access to the outer class attributes and methods.
The work around for this problem: Define all Inner Classes with a parent parameter. This parameter can be used to access the outer class attributes and methods.
class Outer:
def __init__(self):
self.myVar = 100
self.inner = self.Inner(self)
def getDoubleVar(self):
return(self.myVar * 2)
#Define inner class
class Inner:
def __init__(self, parent):
self.parent = parent
#Use the parent variable to access parent class attributes/methods
def printOuterVar(self):
print(self.parent.myVar)
def callOuterMethod(self):
return(self.parent.getDoubleVar())
#Create Instance of Outer Class
outer = Outer()
#Display myVar
print("Display myVar")
print(outer.myVar)
#Execute Outer Method
print("\nExecute Outer Method")
print("val = outer.getDoubleVar()")
val = outer.getDoubleVar()
print("val: {0}".format(val))
#Execute Inner Method
print("\nExecute Inner Method")
print("outer.inner.printOuterVar()")
outer.inner.printOuterVar()
#Execute Inner Method That Calls Outer Method
print("\nExecute Inner Method That Calls Outer Method")
val = outer.inner.callOuterMethod()
print("val = outer.inner.callOuterMethod()")
print("val: {0}".format(val))
#Create Instance of Inner Class Separately
print("\nInstantiate Inner Class Separately")
#Note that you provide the current outer instance as the parent parameter
print("Note that you provide the current outer instance as the parent parameter")
print("myInner = outer.Inner(outer)")
myInner = outer.Inner(outer)
#Call Inner Method
print("\nCall Inner Method")
print("myInner.printOuterVar()")
myInner.printOuterVar()
print("finished")
Upvotes: 0
Reputation: 602635
I would suggest
class Complicated:
pass
class _Utility1:
pass
class _Utility2:
pass
and put all this in a module of its own. The leading _
indicates that the utility classes are meant for internal use only (and for what it's woth, they won't get imported by from module import *
; but I don't like this anyway).
Edit: Citing from PEP 8:
Classes for internal use have a leading underscore in addition.
Upvotes: 7
Reputation:
Whether I use an inner class or outer class largely depends on whether I expect to override the type, either in a subclass or on a per-instance basis:
class Foo(object):
normalize = str
def process(self, input):
# Do some stuff in here...
return self.normalize(output)
class UniFoo(Foo):
normalize = unicode
class TotallyMungedFoo(Foo):
class normalize(object): ...
If I don't expect to need (or explicitly don't want) behavior like this, I use classes in the same module, but only include the "important" one in my __all__
declaration.
Upvotes: 0
Reputation: 3451
I use the single underscore as a prefix to classes that are internal to a python packages. I think this is a common python pattern:
class Complicated:
pass
class _Utility1:
pass
class _Utility2:
pass
Upvotes: 1