Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardise on class constructor methods for object creation from different formats #278

Open
5 of 8 tasks
connortann opened this issue Nov 9, 2021 · 0 comments
Open
5 of 8 tasks
Labels
refactor Restructure or simplification

Comments

@connortann
Copy link
Collaborator

connortann commented Nov 9, 2021

I propose we use class constructor methods for all methods that instantiate objects from external input formats. This is a common "pythonic" pattern: see for example pd.DataFrame.from_dict(), pd.DataFrame.from_records().

Andy & I have been trying to roll out this pattern across resqpy, but currently we're a bit inconsistent and many classes need to be refactored. It is already implemented in a number of classes, for example resqpy.well.DeviationSurvey.from_data_frame .

How constructor methods are called by users

Class methods are called from the class directly, without first having to instantiate an object:

# Good
survey1 = DeviationSurvey.from_data_frame(df=df)
survey2 = DeviationSurvey.from_ascii_file(path="file.dat")

This is cleaner than first instantiating a messy "empty" object, and then calling another method to populate the attributes:

# Not as good
survey = DeviationSurvey(data=None)
survey.from_data_frame(df)

Rationale

  • The init method becomes simpler: does not need any logic relating to file formats, makes it clearer what are the important data attributes
  • Init method can assume data is actually given when class is created: can do validation, type checking et cetera in one place.
  • Each constructor method is completely independent, the loading is done before the object is instantiated.

Example implementation

class DeviationSurvey:

    def __init__(self, data):
       # Arguments are the fundamental data needed to instantiate the class
        self.data = validate_inputs(data)    # Data is a mandatory attribute
    
    @classmethod
    def from_file(cls, file):
        with open(file) as f:
            data = f.read()
        return cls(data=data)  # This calls the init method

Checklist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactor Restructure or simplification
Projects
None yet
Development

No branches or pull requests

2 participants