How to Separate the Functions of a Class into Multiple Files

Splitting python class into multiple files

1st I must say that you won't gain any maintenance out of this ... but for example lets move the create_module_gui to another class

in a new file: creategui.py

class CreateGUI(object):

def create_module_gui(self, *args):
module_gui = subwindowGUI.Ui_ModuleWindow()
module_gui.setupUi(module_gui)

self.myTabs.addTab(module_gui, _('New tab'))
self.myTabs.setCurrentWidget(module_gui)

in your code:

from GUI import mainGUI
from GUI import subwindowGUI
from creategui import CreateGUI

class MyApp(QMainWindow, mainGUI.Ui_MainWindow, CreateGUI):
#yay you have your create_module_gui method now...

Now you can also just put create_module_gui as a function in another file and call it with self as the first param...

Separate functions from the same class in multiple files

The machine doesn't care. So the sole driver for your decision will be the human at the center of it all: the developer.

Consider a book. Would you rather have the book as a complete entity, perhaps separated into chapters, or chunked into paragraphs on little pieces of paper? Locality of reference is important, and the implementation of a class should fit into a single file. Implementations of closely related classes could also all go into a single file if the code is easier to maintain that way. Heck, the entire project could go into a single file if it's small enough.

Personally, I find that things get hard to navigate after a single .cpp file is more than 3-4k lines long. But having lots of files with less than 500 lines each in them is just as painful. IDEs reduce some of the pain by providing easier navigation between the uses, declarations and definitions, of course, but files too small are almost never helpful in project comprehension. E.g. Java's insistence on one-public-class-per-file and on a 1:1 relationship between is a scourge in this respect and is at odds with what we know of cognitive psychology.

Too many functions in java class, how to split in multiple files

Refactor everything carefully with a lot of tests so you don't break anything. Surely you can extract some functions to a different class.

50K lines in one file is a lot. Use composition to extract a certain subset of instructions (adhere to the Single Responsibility Principle!) into a separate class and simply keep a field that points to an instance of this class.

If you're asking if you can just split the same class over multiple files (like C#'s partial): no, you can't.

decouple function and class into separate files

Having a module that is thousands of lines long isn't that bad. You may not actually need to break it up into different modules. It is common to have a module that has a function alongside a class like your tensor and Tensor in the same module, and there is no reason for mean to be split up into a separate function as that code can just be placed directly in Tensor.mean.

A module should have a specific purpose and be a self contained unit around that purpose. If you are splitting things up just to have smaller files, then that is only going to make your codebase worse. However, large modules are a sign that things may need to be refactored. If you can find good ways of refactoring ideas in the code into smaller ideas, then those smaller units could be given their own modules, otherwise, keep everything as a bigger module.

As for how you can split up code that is coupled together. Here is one of way of splitting up the code into the modules you indicated. Since you have a function, the tensor function, that you would like people to use to get an instance of your Tensor class, it seemed like creating a Python package would be somewhat sensible since packages come with an __init__.py file that is used for establishing the API ie your tensor function. I put the tensor function directly in the __init__.py file, but if the function is pretty large, it can be broken out into a separate module, since the __init__.py file is just suppose to give you an overview of the API being created.

# --- main.py ----

from tensor import tensor

print(tensor([1,2,3]).mean())
# --- tensor/__init__.py ----

'''
Add some documentation here
'''

def tensor(data):
return Tensor(data)

from tensor.Tensor import Tensor
# --- tensor/Tensor.py ----

from tensor import helper

class Tensor:
def __init__(self,data):
self.data=data
def __repr__(self):
return f'Tensor({str(self.data)})'
def mean(self):
return helper.mean(self.data)
# --- tensor/helper.py ----

import numpy as np
from . import tensor

def mean(data):
value=np.mean(data)
return tensor(value)

About circular dependencies

Tensor and helper are importing each other, and this is ok. When the helper module imports Tensor, and Tensor in turn imports helper again, helper will just continue loading normally, and then when it is done Tensor will finish loading. Now if you had stuff on the module level (code outside of your function/classes) being executed when the module is first loaded, and it is dependent on functionality in another module that is only partially loaded, then that is when you run into problems with circular dependencies.

Using classes that don't exist yet

I can add to the __init__ file

def some_function(): 
return DoesntExist()

and your code would still run. It doesn't look for a class named Tensor until it is actually running the tensor function. If we did the following then we would get an error about Tensor not existing.

def tensor(data):
return Tensor(data)
tensor()
from tensor.Tensor import Tensor

because now we are running the tensor function before the import and it can't find anything named Tensor.

The order of stuff in __init__

If you switch the order around you will have

__init__ imports Tensor imports helper imports __init__ again

as it tries to grab the tensor function, but it can't as the __init__ function can't proceed past the the line that imports Tensor until that import has been completed.

Now with the current order we have,

__init__ defines tensor, sees the import statement, and saves its current progress as a partial import
The same imports happen (__init__ imports Tensor imports helper imports __init__ looking for a tensor function)
This time we look at the partial import for the tensor function, find it, and we are able to continue on using that.

I didn't think about any of that when I put things in that order. I just wrote out the code, got the circular import error, switched the order around, and didn't think about what was going on until you asked about it.

And now that I think about it, the following would have worked too.

The order of things in the __init__ file will no longer matter.

from tensor.Tensor import Tensor

def tensor(data):
return Tensor(data)

And then in helper.py

import numpy as np
import tensor

def mean(data):
value=np.mean(data)
return tensor.tensor(value)

The difference is that now instead of specifically asking that the tensor function exist when the module is imported by trying to do from . import tensor, we are doing import tensor (which is importing the tensor package and not the function). And now, whenever the the mean function gets run, we are going to do tensor.tensor(value) to get the tensor function inside our tensor package.

How to split a PHP class to separate files?

a-priori PHP doest not give you this feature by language construction, the whole class must be in a single file.

Now there are tricks that could do the stuff, but they are quite heavy CPU demanding:

You can for example dissociate your classes between different files, then load the files and build a single string with the whole code, then do an eval(string) to interprete the classes and build them into the runnable code area.

not really a good idea btw for many reasons

In Java, can we divide a class into multiple files

No, the whole of a class has to be in a single file in Java.

If you're thinking of C#'s "partial types" feature, there's no equivalent in Java. (If you weren't thinking of C#, ignore this :)

How do I split a TypeScript class into multiple files?

You can't.

There was a feature request to implement partial classes, first on CodePlex and later on GitHub, but on 2017-04-04 it was declared out-of-scope. A number of reasons are given, the main takeaway seems to be that they want to avoid deviating from ES6 as much as possible:

TypeScript already has too many TS-specific class features [...] Adding yet another TS-specific class feature is another straw on the camel's back that we should avoid if we can. [...] So if there's some scenario that really knocks it out of the park for adding partial classes, then that scenario ought to be able to justify itself through the TC39 process.



Related Topics



Leave a reply



Submit