简体   繁体   English

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

[英]How can I separate functions of class into multiple files?

I know this has been asked a couple of times, but I couldn't quite understand the previous answers and/or I don't think the solution quite represents what I'm shooting for.我知道这已经被问过几次了,但我不太明白以前的答案和/或我认为该解决方案不能完全代表我的目标。 I'm still pretty new to Python, so I'm having a tough time figuring this out.我对 Python 还是很陌生,所以我很难弄清楚这一点。

I have a main class that has a TON of different functions in it.我有一个主类,其中包含大量不同的功能。 It's getting hard to manage.越来越难管了。 I'd like to be able to separate those functions into a separate file, but I'm finding it hard to come up with a good way to do so.我希望能够将这些函数分离到一个单独的文件中,但我发现很难想出一个好的方法来做到这一点。

Here's what I've done so far:这是我到目前为止所做的:

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

I do this because if I do:我这样做是因为如果我这样做:

obj_1 = MainClass()

I want to be able to do:我希望能够做到:

obj_1.long_func_1(a, b)

instead of:代替:

separate.long_func_1(obj_1, a, b)

I know this seems kind of nit-picky, but I want just about all of the code to start with obj_1.我知道这看起来有点挑剔,但我希望几乎所有代码都以obj_1. so there isn't confusion.所以没有混淆。

Is there a better solution that what I'm currently doing?有没有比我目前正在做的更好的解决方案? The only issues that I have with my current setup are:我当前设置的唯一问题是:

  1. I have to change arguments for both instances of the function我必须更改函数的两个实例的参数
  2. It seems needlessly repetitive似乎是不必要的重复

I'm actually surprised this isn't a duplicate.我真的很惊讶这不是重复的。 I saw some similar questions and I think there is nowhere a concise answer, so here is how I do it:我看到了一些类似的问题,我认为没有一个简洁的答案,所以我是这样做的:

  1. Class (or group of) is actually a full module.类(或组)实际上是一个完整的模块。 You don't have to do it this way, but if you're splitting a class on multiple files I think this is 'cleanest' (opinion).你不必这样做,但如果你在多个文件上拆分一个类,我认为这是“最干净的”(意见)。
  2. The definition is in __init__.py , methods are split into files by a meaningful grouping.定义在__init__.py ,方法通过有意义的分组拆分为文件。
  3. A method file is just a regular python file with functions, except you can't forget 'self' as a first argument.方法文件只是一个带有函数的常规 python 文件,除非您不能忘记将“self”作为第一个参数。 You can have auxiliary methods here, both taking self and not.你可以在这里有辅助方法,无论是采取self还是不采取。
  4. Methods are imported directly into the class definition.方法直接导入到类定义中。

Suppose my class is some fitting gui (this is actually what I did this for first time).假设我的类是一些合适的 gui(这实际上是我第一次这样做)。 So my file hierarchy may look something like所以我的文件层次结构可能看起来像

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

So plot stuff will have plotting methods, fit stuff contains fitting methods, and data stuff contains methods for loading and handling of data - you get the point.因此,绘图内容将具有绘图方法,拟合内容包含拟合方法,数据内容包含加载和处理数据的方法-您明白了。 By convention I mark the files with a _ to indicate these really aren't meant to be imported directly anywhere outside the module.按照惯例,我用_标记文件以表明这些文件实际上并不打算直接导入模块之外的任何地方。 So _plotsuff.py for example may look like:所以_plotsuff.py例如可能看起来像:

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

etc. Now the important thing is __init__.py :等等。现在重要的是__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
     from ._static_example import something

     #Some more small functions
     def printHi(self):
         print("Hello world")

     #static methods need to be set
     somthing = staticmethod(something)

Tom Sawyer mentions PEP-8 recommends putting all imports at the top, so you may wish to put them before __init__ , but I prefer it this way. Tom Sawyer 提到 PEP-8 建议将所有导入放在顶部,因此您可能希望将它们放在__init__之前,但我更喜欢这种方式。 I have to say, my Flake8 checker does not complain, so likely this is PEP-8 compliant.我不得不说,我的 Flake8 检查器没有抱怨,所以这很可能是 PEP-8 兼容的。

Note the from ... import ... is particularly useful to hide some 'helper' functions to your methods you don't want accessible through objects of the class.请注意from ... import ...对于将某些“辅助”函数隐藏到您不希望通过类的对象访问的方法中特别有用。 I usually also place the custom exceptions for the class in the different files, but import them directly so they can be accessed as Fitter.myexception .我通常也会将类的自定义异常放在不同的文件中,但直接导入它们,以便它们可以作为Fitter.myexception访问。

If this module is in your path then you can access your class with如果这个模块在你的路径中,那么你可以访问你的类

from mymodule import Fitter
f = Fitter()
f.load('somefile') #Imported method
f.plot()           #Imported method

Not completely intuitive, but not to difficult either.不完全直观,但也不难。 The short version for your specific problem was your were close - just move the import into the class, and use您的特定问题的简短版本是您的关闭 - 只需将导入移动到类中,然后使用

from separate import long_func_1

and don't forget your self !不要忘记你的self

I use the approach I found here It shows many different approaches, but if you scroll down to the end it the preferred method is to basically go the opposite direction of @Martin Pieter's suggestion which is have a base class that inherits other classes with your methods in those classes.我使用我在这里找到的方法它显示了许多不同的方法,但是如果您向下滚动到最后,首选方法基本上是与@Martin Pieter 的建议相反的方向,该建议具有一个继承其他类的基类与您的方法在那些课上。

so folder structure something like:所以文件夹结构类似于:

_DataStore/
    __init__.py
    DataStore.py
    _DataStore.py

So your base class would be:所以你的基类将是:

# 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

Then your Mixin class:然后你的 Mixin 类:

# _DataStore.py

class Mixin:

    def big_method(self):
        return self._b

    def huge_method(self):
        return self._c

Your separate methods would be located in other appropriately named files, in this example it is just _DataStore.您的单独方法将位于其他适当命名的文件中,在此示例中它只是 _DataStore。

I am interested to hear what others think about this approach, I showed it to someone at work and they were scared by it, but it seemed to be a clean and easy way to separate a class into multiple files.我很想听听其他人对这种方法的看法,我向工作中的某个人展示了它,他们被它吓到了,但这似乎是将一个类分成多个文件的一种干净而简单的方法。

Here is an implementation of @Martijn Pieters♦'s comment to use subclasses:这是@Martijn Pieters♦ 使用子类的注释的实现:

main.py : 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 : 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)
....

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM