Is there any Python equivalent to partial classes?

Class definitions containing hundreds of lines do occur "in the wild" (I have seen some in popular open-source Python-based frameworks), but I believe that if you ponder what the methods are doing, it will be possible to reduce the length of most classes to a manageable point. Some examples:

  • Look for places where mostly the same code occurs more than once. Break that code out into its own method and call it from each place with arguments.
  • "Private" methods that do not use any of the object state can be brought out of the class as stand-alone functions.
  • Methods that should be called only under certain conditions may indicate a need to place those methods in a subclass.

To directly address your question, it is possible to split up the definition of a class. One way is to "monkey-patch" the class by defining it and then adding outside functions to it as methods. Another is to use the built-in type function to create the class "by hand", supplying its name, any base classes, and its methods and attributes in a dictionary. But I do not recommend doing this just because the definition would be long otherwise. That sort of cure is worse than the disease in my opinion.


I've previously toyed around with something similar. My usecase was a class hierarchy of nodes in an abstract syntax tree, and then I wanted to put all e.g. prettyprinting functions in a separate prettyprint.py file but still have them as methods in the classes.

One thing I tried was to use a decorator that puts the decorated function as an attribute on a specified class. In my case this would mean that prettyprint.py contains lots of def prettyprint(self) all decorated with different @inclass(...)

A problem with this is that one must make sure that the sub files are always imported, and that they depend on the main class, which makes for a circular dependency, which may be messy.

def inclass(kls):
    """
    Decorator that adds the decorated function
    as a method in specified class
    """
    def _(func):
        setattr(kls,func.__name__, func)
        return func
    return _

## exampe usage
class C:
    def __init__(self, d):
        self.d = d

# this would be in a separate file.
@inclass(C)
def meth(self, a):
    """Some method"""
    print "attribute: %s - argument: %s" % (self.d, a)

i = C(10)
print i.meth.__doc__
i.meth(20)

If your problem really is just working with a large class in an editor, the first solution I'd actually look for is a better way to break down the problem. The second solution would be a better editor, preferably one with code folding.

That said, there are a couple of ways you might break up a class into multiple files. Python lets you use a folder as a module by putting an __init__.py in it, which can then import things from other files. We'll use this capability in each solution. Make a folder called, say, bigclass first.

  1. In the folder put the various .py files that will eventually comprise your class. Each should contain functions and variable definitions for the eventual class, not classes. In __init__.py in the same folder write the following to join them all together.

    class Bigclass(object):
    
        from classdef1 import foo, bar, baz, quux
        from classdef2 import thing1, thing2
        from classdef3 import magic, moremagic
        # unfortunately, "from classdefn import *" is an error or warning
    
        num = 42   # add more members here if you like
    

    This has the advantage that you end up with a single class derived directly from object, which will look nice in your inheritance graphs.

  2. You could use multiple inheritance to combine the various parts of your class. In your individual modules you would write a class definition for Bigclass with parts of the class. Then in your __init__.py write:

    import classdef1, classdef2, classdef3
    
    class Bigclass(classdef1.Bigclass, classdef2.Bigclass, classdef3.Bigclass):
        num = 42   # add more members if desired
    
  3. If the multiple inheritance becomes an issue, you can use single inheritance: just have each class inherit from another one in chain fashion. Assuming you don't define anything in more than one class, the order doesn't matter. For example, classdef2.py would be like:

    import classdef1
    class Bigclass(classdef1.Bigclass):
         # more member defs here
    

    classdef3 would import Bigclass from classdef2 and add to it, and so on. Your __init__.py would just import the last one:

    from classdef42 import Bigclass
    

I'd generally prefer #1 because it's more explicit about what members you're importing from which files but any of these solutions could work for you.

To use the class in any of these scenarios you can just import it, using the folder name as the module name: from bigclass import Bigclass


You can do this with decorators like so:

class Car(object):

    def start(self):
        print 'Car has started'


def extends(klass):
    def decorator(func):
        setattr(klass, func.__name__, func)
        return func
    return decorator

#this can go in a different module/file
@extends(Car)
def do_start(self):
    self.start()


#so can this
car = Car()
car.do_start()

#=> Car has started