Is there any Python equivalent to partial classes?

杀马特。学长 韩版系。学妹 提交于 2019-11-26 08:59:50

问题


Using \"new\" style classes (I\'m in python 3.2) is there a way to split a class over multiple files? I\'ve got a large class (which really should be a single class from an object-oriented design perspective, considering coupling, etc, but it\'d be nice to split over a few files just for ease of editing the class.


回答1:


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




回答2:


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.




回答3:


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)



回答4:


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



回答5:


I've not used it, but this package called partial claims to add support for partial classes.

It seems like there's a few other ways you could implement this yourself as well.

You could implement separate parts of the class as mixins in seperate files, then import them all somewhere and subclass them.

Alternatively, you could implement each of the methods of your class somewhere then in a central file import them and assign them as attributes on a class, to create the whole object. Like so:

a.py:

def AFunc( self, something ):
    # Do something
    pass

b.py:

def BFunc( self, something ):
    # Do something else
    pass

c.py:

import a, b

class C:
    AFunc = a.AFunc
    BFunc = b.BFunc

You could even go so far as to automate this process if you really wanted - loop through all the functions provided by modules a and b and then add them as attributes on C. Though that might be total overkill.

There might be other (possibly better) ways to go about it, but those are the 2 that popped into mind.




回答6:


First off, I don't see how splitting the class into multiple files makes editing any easier. A decent IDE should be able to find any method easily whether in one file or multiple; if you're not using a decent IDE, splitting the class means the maintainer has to guess which file a given method is in, which sounds harder rather than easier.

More fundamentally, this class - so large that you want a special language feature just to support its weight - sounds fundamentally broken. How many lines of code are we talking about? Almost certainly, it would be a better idea to do one of:

  • Refactor duplicated code into fewer, more general primitives
  • Define a base class and extend it with subclasses as Karoly Horvath suggests in comments (this is the closest thing to the 'partial classes' that you're asking for that I would endorse)
  • Define a few separate classes to encapsulate different parts of this class's functionality, and compose this class of instances of those smaller ones.



回答7:


I met the same situation - I want to slipt my class to 2 files. the reason is that - I want part 1 for GUI layout, only layout and another file keeps all function. like c#'s Partial class. one for XAML and another one for functions.




回答8:


First I'd like to say that something this complicated it probably not a good idea just to make finding your place in the class easier - it would be best to add comments, highlight sections etc. However, I see two ways you could do this:

  1. Write the class in several files, then read them in as text, concatenate them and exec the resulting string.

  2. Create a separate class in each file, then inherit them all into a master class as mixins. However, if you're subclassing another class already this could lead to MRO problems. You could get around this by creating a metaclass for your master class which manually resolves the MRO, but this could get messy.

The easiest would be the first option.



来源:https://stackoverflow.com/questions/9638446/is-there-any-python-equivalent-to-partial-classes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!