1

I'm creating a custom class to store information about a CFD simulation results.

Right now the way it is set up is that it instantiates an empty class object, then used a method called load_mesh which calls an external function to read all the information about the mesh, and return a dictionary of all the information. The load_mesh method then assigns a bunch of class attributes from the values in the dictionary.

The problem is that I am planning to store alot more information than just the mesh, and I dont want to have like 1000 attributes to my class object. I want to store then in appropriate containers(?) that each have their own methods.

For example, my code looks like this currently (some stuff omitted that's unnecessary):

class CFD():
    def __init__(self, infile=None):
        self.file = infile

    def load_mesh(self):
        mesh = load_cfd_mesh(self) #calls outside function to load mesh info, uses self.file, returns dict
        self.proj = mesh['proj']
        self.static_items = mesh['static_items']
        self.nnodes = mesh['nnodes']
        self.node_coords = mesh['node_coords']
        self.node_codes = mesh['node_codes']
        self.nelements = mesh['nelements']
        self.element_types = mesh['element_types_str']
        self.node_connectivity = mesh['node_connectivity']
        self.element_node_ids = mesh['element_node_ids']
        self.element_coords = mesh['element_coords']
        self.element_elevs = mesh['element_elevs']
        self.horizontal_units = mesh['horizontal_units']
        self.vertical_units = mesh['vertical_units']

test = CFD('testfile.txt') #instantiate
test.load_mesh() #load mesh information to attributes

Now, I can access any of the mesh information by doing:

test.proj
self.nnodes
self.coords

etc...

But want I want to do is store all of this information in test.mesh, where test.mesh has all of these attributes but also has the method test.mesh.load().

I THINK I can do something like this:

class CFD():
    def __init__(self, infile=None):
        self.file = infile
        self.mesh = None

    def load_mesh(self):
        mesh = load_cfd_mesh(self) #calls outside function to load mesh info, uses self.file, returns dict
        setattr(self.mesh, 'proj', mesh['proj'])
        #etc....

then I'd be able to do:

test = CFD('testfile.txt') #instantiate
test.load_mesh() #load mesh information to attributes
test.mesh.proj

But I can't figure out how to add the load_mesh method to self.mesh?

How is it possible to achieve the following way of doing this:

test = CFD('testfile.txt') #instantiate
test.mesh.load() #load mesh information to attributes
test.mesh.proj

Do I have to define another class within the main class? Like class mesh(self):

Also, if my proposed way of adding attributes to self.mesh doesn't make sense..please help!

15
  • You want to replace a dict with a class with attrbiutes? Except for a little of readability, I wouldn't recommend this. Stick to use a dict: it's a perfectly fine data structure for this. Don't force it into a class just because mydata.some_key seems a tiny bit nicer than mydata['some_key']. Commented Jan 31, 2020 at 13:49
  • ok regardless of how I store the information in self.mesh how can I add the load method to it, the main question is adding a method Commented Jan 31, 2020 at 13:50
  • @00 No, class CFD(): is fine, if a little odd looking. Commented Jan 31, 2020 at 13:51
  • In the end I can do self.mesh['proj']if I want, but how can I load the mesh info by calling self.mesh.load() Commented Jan 31, 2020 at 13:51
  • @chepner There's actually more going into the class I just deleted it for the sake of minimalism for the question..shouldve deleted the paranthesis, but either way Commented Jan 31, 2020 at 13:52

2 Answers 2

3

I think you might be looking for something like a property to lazily load the mesh when needed – I don't really see why there'd be an "empty" mesh object you explicitly have to .load():

class Mesh:
    def __init__(self, filename):
        mesh = load_cfd_mesh(filename)
        self.proj = mesh["proj"]
        self.static_items = mesh["static_items"]
        # ...


class CFD:
    def __init__(self, filename):
        self.filename = filename
        self._mesh = None

    @property
    def mesh(self):
        if not self._mesh:
            self._mesh = Mesh(self.filename)
        return self._mesh


test = CFD("testfile.txt")
print(test.mesh.proj)
Sign up to request clarification or add additional context in comments.

3 Comments

I think this might be exactly what I'm looking for - at work but I'll try it out at some point today and get back to you..appreciated
this is more "how you should do it". you might not want its __init__to do the loading, and keep the loading method on CFD though - because I think code will look strange - on the very first access you'd have to thread cfd.mesh as a callable, cfd.mesh("myfile") and on the subsequent accesses you'd use cfd.mesh.mesh_attr . If the loading is triggered on CFD.__init__ this would be cleaner.
Thanks to both. This is the route I went. I didn't include the load in the init because the meshes could potentially be huge and if it's not needed I don't want to waste time initializing the class instance. It will load once if needed then remain loaded for subsequent calls
2

You can do that with an inner class (below is a simplified code for demonstrating):

class CFD:
    class Mesh:
        def __init__(self, file):
            self._file = file

        def load_mesh(self):
            # implement here your own code...
            print("loading from file", self._file)
            self.proj = "PROJ"

    def __init__(self, file):
        self.mesh = self.__class__.Mesh(file)

5 Comments

thanks, between yours and @AKX 's approach, I think I'll be able to achieve what I'm trying to do.. I'll be able to test this later and get back to you..much appreciated
note that you gain nothing by nesting the class declarations themselves - here class Mesh could be - and probably should - outside the body of class CFD itself. If you look at the hundreds of thousands of projects of web-backend code that use relational databases, where, say, a Person must have an associated instance of Contact, that is the way it is done.
@jsbueno: I gain encapsulation. If the Mesh class is intended to be used outside of the CFD class, then it must be declared outside. If all of its objects are intended to be attributes of CFD objects, then it is better to make it an inner class.
this is not a usual practice, and I hope you at least akcnowledge that. One can have enough encapsoluation by putting the code in the correct module files. It may feel more semantic - and that may be a good thing. Ah - I remember the tricky part of doing that - is that one might think that from inside a Mesh instance you can get to the owner CFD - and there are no implicit mechanisms for it. If needed the owner must be passed explictly to Mesh's __init__. Otherwise than that, the objection comes really just to "flat is better than nested"
Thanks for your help but I ended up making a external class so accepted the other answer. Much appreciated

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.