[Python] how to call a def in another class that in turn calls a def of the caller class

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

[Python] how to call a def in another class that in turn calls a def of the caller class

Post by uwestoehr »

How can I sort out code from a class to another file?

For example I have a large class called "Writer". it has dozens of defs and they call each other. I want to move some defs to another .py file to keep the overview.

My attempt was to take some def from class "Writer" to a new file, put them there into a class called e.g. "ESwriter".
The point is that the defs in calss ESwriter in turn calls some other defs in class Writer. This compiles but when executed the other defs in calss Writer do not return anything.
An example:

Code: Select all

class ESwriter:
    def init(self, solver, directory):
        self.solver = solver
        self.directory = directory
        self.write = writer.Writer(self.solver, self.directory)
    def _handleElectrostaticConstants(self):
        self.write._constant(
            "Permittivity Of Vacuum",
            self.write._convert(self.write.constsdef["PermittivityOfVacuum"], "T^4*I^2/(L^3*M)")
        )
in the Writer class, make the initial call this way:

Code: Select all

ESW = test.ESwriter(self.solver, self.directory)
ESW._handleElectrostaticConstants()
How is this done right?
agren
Posts: 40
Joined: Sat Apr 20, 2019 7:37 am

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by agren »

uwestoehr wrote: Thu Feb 02, 2023 1:03 am

Code: Select all

class ESwriter:
    def init(self, solver, directory):
        self.solver = solver
        self.directory = directory
        self.write = writer.Writer(self.solver, self.directory)
    def _handleElectrostaticConstants(self):
        self.write._constant(
            "Permittivity Of Vacuum",
            self.write._convert(self.write.constsdef["PermittivityOfVacuum"], "T^4*I^2/(L^3*M)")
        )
in the Writer class, make the initial call this way:

Code: Select all

ESW = test.ESwriter(self.solver, self.directory)
ESW._handleElectrostaticConstants()
Sounds like you have a circular dependency, but I believe your code could still run.
If you either could share the working code (before change), a minimal running example (after the change), or both. That would be good to better know what gets called when, and what is supposed to happen.

Something like

Code: Select all

# test.py
import ...

class ESwriter:
    ...

Code: Select all

# writer.py
import ...

class Writer:
    def __init__(self, solver, directory):
        ...
        
    def _convert(self, ...):
        ...
        return ...
        
    def _constant(self, ...):
        ...
    
    constdef = {"PermittivityOfVacuum": ...}
heda
Veteran
Posts: 1348
Joined: Sat Dec 12, 2015 5:49 pm

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by heda »

splitting a class in 2 and use them as they were not split?
inheritance and super? (regardless if same file or not)...

Code: Select all

#from . import A

class A():
    def __init__(self):
        self.a = 1
        
    def mod_a(self, new):
        self.a = new
        
    def printa(self):
        print(self.a)
        
class B(A):
    def __init__(self):
        super().__init__()
        
    def new_a_value(self, a):
        self.mod_a(a)



b = B()
b.printa()
b.new_a_value(2)
b.printa()

if args, super().__init__(*args, **kwargs) will pass all of it to instance A.
User avatar
Roy_043
Veteran
Posts: 8450
Joined: Thu Dec 27, 2018 12:28 pm

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by Roy_043 »

Can't you just leave out __init__ in class B?
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by uwestoehr »

agren wrote: Thu Feb 02, 2023 9:25 pm If you either could share the working code (before change), a minimal running example (after the change), or both. That would be good to better know what gets called when, and what is supposed to happen.
Thanks.

The file that should be split is attached:
writer.py
(77.39 KiB) Downloaded 26 times
From this file the defs named "*ElectrostaticSolver" of the class "Writer" should be sorted out. Here is my attempt to sort them out to a new file:
electrostatic_writer.py
(7.77 KiB) Downloaded 21 times
agren
Posts: 40
Joined: Sat Apr 20, 2019 7:37 am

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by agren »

Do I understand correctly that you have added something like this in writer.py?

Code: Select all

    def _handleElectrostatic(self):
        ...
        if activeIn:
            ESW = test.ESwriter(self.solver, self.directory)
            ESW._handleElectrostaticConstants()
If so. You're creating a new instance of Writer when you create an instance of ESwriter. That looks suspicious. If you just want to split the code into separate files this should be enough:

Code: Select all

# writer.py
    def _handleElectrostatic(self):
        ...
        if activeIn:
            ESW = test.ESwriter(this, self.solver)
            ESW._handleElectrostaticConstants()
            ...

Code: Select all

# electrostatic_writer.py
class ESwriter:
    def __init__(self, writer, solver):
        self.writer = writer
        self.solver = solver
    ...
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by uwestoehr »

agren wrote: Fri Feb 03, 2023 10:05 pm Do I understand correctly that you have added something like this in writer.py?
Yes and this is why I am stuck. I only want to split the too long writer.py but get a circular dependency.
agren wrote: Fri Feb 03, 2023 10:05 pm If you just want to split the code into separate files this should be enough:
many thanks.
However this still elads to a circular dependency.

I have now this:

Code: Select all

# writer.py
from .equations import electrostatic_writer as ES_writer
class Writer(object):
    def __init__(self, solver, directory, testmode=False):
        self.analysis = solver.getParentGroup()
        ...
    def _handleElectrostatic(self):
        ...
        if activeIn:
            ESW = ES_writer.ESwriter(this, self.solver)
            ESW._handleElectrostaticConstants()
            ...

Code: Select all

# electrostatic_writer.py
class ESwriter:
    def __init__(self, writer, solver):
        self.writer = writer
        self.solver = solver
    def _getElectrostaticSolver(self, equation):
        # check if we need to update the equation
        self._updateElectrostaticSolver(equation)
        ...
This gives me this error:

Code: Select all

File "D:\FreeCAD-build\Mod\Fem\femsolver\elmer\writer.py", line 98, in write_solver_input
      self._handleElectrostatic()
    File "D:\FreeCAD-build\Mod\Fem\femsolver\elmer\writer.py", line 857, in _handleElectrostatic
      ESW = ES_writer.ESwriter(this, self.solver)
  NameError: name 'this' is not defined
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by uwestoehr »

When I replace the unknown "this" by "self"

I get however, this error:

Code: Select all

05:59:31    File "D:\FreeCAD-build\Mod\Fem\femsolver\elmer\writer.py", line 857, in _handleElectrostatic
05:59:31      ESW = ES_writer.ESwriter(self, self.solver)
05:59:31    File "D:\FreeCAD-build\Mod\Fem\femsolver\elmer\equations\electrostatic_writer.py", line 41, in __init__
05:59:31      self.write = writer.Writer(self.solver, self.directory)
05:59:31    File "D:\FreeCAD-build\Mod\Fem\femsolver\elmer\writer.py", line 79, in __init__
05:59:31      self.analysis = solver.getParentGroup()
05:59:31  AttributeError: 'Writer' object has no attribute 'getParentGroup'
What I need is that the def "_getElectrostaticSolver" from the ESWriter calls uses the defs in the already loaded Writer class and not to re-initialize the Writer class.
agren
Posts: 40
Joined: Sat Apr 20, 2019 7:37 am

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by agren »

uwestoehr wrote: Sun Feb 05, 2023 4:36 am

Code: Select all

NameError: name 'this' is not defined
Oops, sorry. Should be self.

uwestoehr wrote: Sun Feb 05, 2023 5:02 am When I replace the unknown "this" by "self"

I get however, this error:

Code: Select all

05:59:31    File "D:\FreeCAD-build\Mod\Fem\femsolver\elmer\writer.py", line 857, in _handleElectrostatic
05:59:31      ESW = ES_writer.ESwriter(self, self.solver)
05:59:31    File "D:\FreeCAD-build\Mod\Fem\femsolver\elmer\equations\electrostatic_writer.py", line 41, in __init__
05:59:31      self.write = writer.Writer(self.solver, self.directory)
...
Looks like ESWriter.__init__ does not look like this:

Code: Select all

    def __init__(self, writer, solver):
        self.writer = writer
        self.solver = solver
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

Re: [Python] how to call a def in another class that in turn calls a def of the caller class

Post by uwestoehr »

agren wrote: Sun Feb 05, 2023 9:24 am Looks like ESWriter.__init__ does not look like this:

Code: Select all

    def __init__(self, writer, solver):
        self.writer = writer
        self.solver = solver
But it does. See attached:
electrostatic_writer.py
(7.6 KiB) Downloaded 11 times
Post Reply