Is this possible please? I have done some searching but it is hard to
narrow down Google searches to this question. What I would like to do
is, for example:
1) define a class Foo in file test.py... give it some methods
2) define a file test2.py which contains a set of methods that are
methods of class Foo defined in test.py.
Technically, yes, this is possible, but you shouldn't need to do it.
Needing to split a single class across multiple files is a sign of bad
design. If the class is that huge, then it probably does too many things
and should be broken up into multiple classes and then reassembled using
composition.
[...]
In short I would like to distribute code for one class across multiple
files so a given file doesn't get ridiculously long.
What do you call "ridiculously long"?
One of the largest modules in the Python standard library is decimal. I
consider decimal to be about as big as a single module should get: over
5000 lines of code. Any larger, and you should consider splitting it into
a package with multiple files.
But note that those 5000 lines include over 500 lines of comments,
details documentation, plenty of blank lines, 14 public classes, 3 public
functions, and at least 17 private functions or classes. The main class,
decimal.Decimal, is about 2800 lines of code.
If your class is smaller than that, I don't think you need to worry about
splitting it.
But let's suppose you really do have a good reason to split the class
into multiple files. And not just "because that's how I'd do it in Java".
Suppose you have a class Spam, and it has two methods, spam() and eggs().
You want to split the methods into different files. (Perhaps you want to
win a bet.) There are three main possibilities:
(1) Inheritance.
(2) Composition or delegation.
(3) Dynamic code injection.
Let's start with inheritance.
In module a.py, create a class:
class EggMixin:
def eggs(self):
c = self.colour
print("%s eggs go well with %s spam" % (c, c))
Notice that as a mixin, EggsMixin isn't required to provide the
self.colour attribute.
Technically it isn't necessary for this to be a mixin, but it is probably
the best design.
Now in module main.py, create the Spam class you really want, using
multiple inheritance to inherit from the "real" superclass and the mixin:
import a
class Spam(SpamParent, a.EggMixin):
def __init__(self, colour='green'):
print("Spam spam spam LOVELY SPAM!!!")
self.colour = colour
def spam(self, n):
return "spam!"*n
By the way, SpamParent is optional. If you don't need it, just leave it
out.
Now, on to composition. First, let's redesign the egg class in a.py:
class Egg:
def __init__(self, owner):
self.owner = owner
def eggs(self):
c = self.owner.colour
print("%s eggs go well with %s spam" % (c, c))
And in main.py:
import a
class Spam(object):
def __init__(self, colour='green'):
print("Spam spam spam LOVELY SPAM!!!")
self.colour = colour
# Create an Egg that has this Spam instance as the owner.
egg = a.Egg(owner=self)
# And store it for later use.
self._egg = egg
def spam(self, n):
return "spam!"*n
def eggs(self):
# Delegate to the saved egg.
return self._egg.eggs()
Last but not least, lets try dynamic code injection. In a.py, create a
function using a placeholder self parameter:
def eggs(self):
c = self.colour
print("%s eggs go well with %s spam" % (c, c))
And here is your main module:
import a
class Spam(object):
def __init__(self, colour='green'):
print("Spam spam spam LOVELY SPAM!!!")
self.colour = colour
def spam(self, n):
return "spam!"*n
# Add the extra method that we want.
Spam.eggs = a.eggs
So now you have three ways of doing something that shouldn't be done