Python:如何将类的功能分成多个文件?

时间:2017-11-29 21:08:57

标签: python file object decorator

我知道这已被问了好几次,但我不能理解以前的答案和/或我认为解决方案并不能代表我正在拍摄的内容。我还是Python的新手,所以我很难搞清楚这一点。

我有一个主要类,其中包含不同功能的TON。它变得越来越难以管理。我希望能够将这些功能分成一个单独的文件,但我发现很难找到一个好方法。

这是我到目前为止所做的:

main.py

import separate

class MainClass(object):
    self.global_var_1 = ...
    self.global_var_2 = ...

    def func_1(self, x, y):
        ...
    def func_2(self, z):
        ...
    # tons of similar functions, and then the ones I moved out:

    def long_func_1(self, a, b):
        return separate.long_func_1(self, a, b)

separate.py

def long_func_1(obj, a, b):
    if obj.global_var_1:
        ...
    obj.func_2(z)
    ...
    return ...
# Lots of other similar functions that use info from MainClass

我这样做是因为如果我这样做:

obj_1 = MainClass()

我希望能够做到:

obj_1.long_func_1(a, b)

而不是:

separate.long_func_1(obj_1, a, b)

我知道这似乎有点挑剔,但我想要的所有代码都以obj_1.开头,所以不会产生混淆。

我目前正在做的是否有更好的解决方案?我目前设置的唯一问题是:

  1. 我必须更改函数
  2. 的两个实例的参数
  3. 似乎不必重复

3 个答案:

答案 0 :(得分:10)

我真的很惊讶这不是重复。我看到了一些类似的问题,我认为没有一个简洁的答案,所以这就是我如何做到的:

  1. Class(或group of)实际上是一个完整的模块。你不必这样做,但是如果你在多个文件上拆分一个类,我认为这是“最干净的”(意见)。
  2. 定义在__init__.py中,方法通过有意义的分组分割成文件。
  3. 方法文件只是一个带有函数的常规python文件,除了你不能忘记'self'作为第一个参数。你可以在这里使用辅助方法,而不是self
  4. 将方法直接导入到类定义中。
  5. 假设我的班级是一些适合的gui(这实际上是我第一次这样做)。所以我的文件层次结构可能类似于

    mymodule/
         __init__.py
         _plotstuff.py
         _fitstuff.py
         _datastuff.py
    

    因此,绘图方法将具有绘图方法,适合的东西包含拟合方法,数据包含用于加载和处理数据的方法 - 您明白了。按照惯例,我使用_标记文件,以指示这些文件实际上并不打算直接导入模块外的任何位置。所以_plotsuff.py例如可能如下:

    def plot(self,x,y):
         #body
    def clear(self):
         #body
    

    等。现在重要的是__init__.py

    class Fitter(object):
         def __init__(self,whatever):
             self.field1 = 0
             self.field2 = whatever
    
         #Imported methods
         from ._plotstuff import plot, clear
         from ._fitstuff  import fit
         from ._datastuff import load
    
         #Some more small functions
         def printHi(self):
             print("Hello world")
    
         #I think static methods have to be here
         @staticmethod
         def something(argumentIsNotSelf):
             print('yay')
    

    Tom Sawyer提到PEP-8建议将所有导入设置在顶部,因此您可能希望将它们放在__init__之前,但我更喜欢这种方式。

    注意from ... import ...对于隐藏您不希望通过类对象访问的方法的某些“帮助”函数特别有用。我通常也会将类的自定义异常放在不同的文件中,但直接导入它们以便可以Fitter.myexception访问它们。

    如果此模块在您的路径中,那么您可以使用

    访问您的班级
    from mymodule import Fitter
    f = Fitter()
    f.load('somefile') #Imported method
    f.plot()           #Imported method
    

    不完全直观,但也不困难。针对您的特定问题的简短版本就是您的关闭 - 只需将导入移动到类中,然后使用

    from separate import long_func_1
    

    并且不要忘记您的self

答案 1 :(得分:1)

我使用发现的方法here 它显示了许多不同的方法,但是如果您滚动到最后,则首选方法是基本上与@Martin Pieter的建议相反,该建议的基类继承了那些类中的方法。

文件夹结构如下:

_DataStore/
    __init__.py
    DataStore.py
    _DataStore.py

所以您的基类将是:

# DataStore.py

import _DataStore

class DataStore(_DataStore.Mixin): # Could inherit many more mixins

    def __init__(self):
        self._a = 1
        self._b = 2
        self._c = 3

    def small_method(self):
        return self._a

然后您的Mixin类:

# _DataStore.py

class Mixin:

    def big_method(self):
        return self._b

    def huge_method(self):
        return self._c

您的单独方法将位于其他适当命名的文件中,在本示例中,它只是_DataStore。

我很想听听其他人对这种方法的看法,我向工作中的人展示了这种方法,但他们对此感到害怕,但这似乎是一种将类拆分为多个文件的干净便捷的方法。

答案 2 :(得分:0)

这是@Martijn Pieters♦关于使用子类的注释的实现:

main.py

from separate import BaseClass

class MainClass(BaseClass):
    def long_func_1(self, a, b):
        if self.global_var_1:
            ...
        self.func_2(z)
        ...
        return ...
    # Lots of other similar functions that use info from BaseClass

separate.py

class BaseClass(object):

    # You almost always want to initialize instance variables in the `__init__` method.
    def __init__(self):
        self.global_var_1 = ...
        self.global_var_2 = ...

    def func_1(self, x, y):
        ...
    def func_2(self, z):
        ...
    # tons of similar functions, and then the ones I moved out:
    #
    # Why are there "tons" of _similar_ functions?
    # Remember that functions can be defined to take a
    # variable number of/optional arguments, lists/tuples
    # as arguments, dicts as arguments, etc.

from main import MainClass
m = MainClass()
m.func_1(1, 2)
....