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__
importsTensor
importshelper
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__
definestensor
, sees the import statement, and saves its current progress as a partial import
The same imports happen (__init__
importsTensor
importshelper
imports__init__
looking for atensor
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
Python Beautifulsoup Extract Text Between Element
How to Change a Module Variable from Another Module
Multiprocessing in Python - Sharing Large Object (E.G. Pandas Dataframe) Between Multiple Processes
How Does the Key Argument in Python's Sorted Function Work
Can Existing Virtualenv Be Upgraded Gracefully
Executing Command Using Paramiko Exec_Command on Device Is Not Working
Create PDF from a List of Images
Add Params to Given Url in Python
Group by Pandas Dataframe and Select Latest in Each Group
Python Attributeerror: 'Module' Object Has No Attribute 'Serial'
Programmatically Searching Google in Python Using Custom Search
How to Loop Through All But the Last Item of a List
How to Extract an Arbitrary Line of Values from a Numpy Array
Add 'Decimal-Mark' Thousands Separators to a Number