1

I have a class representing an Atom, and it has two sets of coordinates, one of these sets is cartesian, and I would like to follow best architectural practices to get that information out of the class.

Previously I have created multiple class methods for getting different types of attributes, but I feel this isn't pythonic, and is unnecessarily cluttering my code, however I am not sure what the solution would generally be.

As it may help someone to answer, please see the Atom class below:

class Atom():

    def __init__(self, element, x_coord, y_coord, z_coord):
        '''
        Instantiate new atom object.
        '''
        #Check information is correct
        if not isinstance(element, str):
            raise ValueError('Element must be a string.')
        if not isinstance(x_coord, int) and not isinstance(x_coord, float):
            raise ValueError('All coordinates must be numeric, x is not.')
        if not isinstance(y_coord, int) and not isinstance(y_coord, float):
            raise ValueError('All coordinates must be numeric, y is not.')
        if not isinstance(z_coord, int) and not isinstance(z_coord, float):
            raise ValueError('All coordinates must be numeric, z is not.')
        self.coordinates = np.array([x_coord, y_coord, z_coord]).astype(float)
        self.cartesian = None
        self.element = element

    def __repr__(self):
        '''
        Atom representation.
        '''
        x, y, z = list(self.coordinates)
        return f"Atom('{self.element}', {x}, {y}, {z})"

    def __copy__(self):
        x, y, z = [float(x) for x in list(self.coordinates)]
        return Atom(self.element, x, y, z)

    def set_cartesian(self, vector_space):
        '''
        Set the cartesian coordinates of the atom, based on a vector space -
        generally that of a unitcell. Requires column vectors.
        '''
        self.cartesian = vector_space @ self.coordinates.T

I would preferably like a single method to handle all attributes, to keep the class uncluttered. I understand I could just use "class.attribute", but as I understand it this can cause code to break long term if you ever want to rename something.

4
  • 1
    I don't get your point. Whatever you use somewhere, you will break it if you rename it and don't update the references. Commented May 12, 2021 at 16:59
  • I guess it's the idea of writing a method, which encapsulates the attribute, that never changes, regardless of what you rename the attribute. However, I could be over thinking it, would you normally use "class.attribute" to get attribute access? Commented May 12, 2021 at 17:03
  • 1
    If you need to use a class that you made sometime in the past but want the attributes to have different names don't change the existing class, write an adapter and use the original class as-is. Commented May 12, 2021 at 17:31
  • Thanks, that's really helpful. So you would recommend using "class.attribute" generally, and then an adapter where necessary? Commented May 12, 2021 at 17:51

1 Answer 1

3

There are a few ways you could approach this. A couple things to keep in mind:

  • Python isn't heavily typed -- in fact, it's barely typed at all
  • It's often useful to think in terms of C++ when writing python code

Now, it sounds to me like you want to have a single method that returns most, if not all, of Atom's attributes. If I were to tackle this in C++, I would most likely create a struct datatype to use and use something like Atom.GetAttributtes() to return variable of that struct type.

However, this is Python, so we get to take advantage of point #1: Python isn't heavily typed.

Thus, you can simply have Atom.GetAttrbutes() return a list, tuple, or array containing all your attributes (you could even nest an array contains your cartesian coordinates inside a list with your other attributes)

However, I'm not sure what you mean when you say that it "isn't pythonic" to have multiple methods get different attributes data. I'll turn your attention to point #2: it's often useful to think in terms of C++ when writing python code.

In C++ having multiple methods (called member functions) is absolutely the way you handle returning attributes (called member variables), so this is a perfectly fine way of doing thing in python as well. This is because having several different function return different attribute will make your program run faster. Why? because if you take the method above (returning your attributes as a list, tuple, or array) and make the the only way to access your attributes, you'll run into situations where, say, you only wanted the element of an atom, but now you have to get all the data (slower, because python has to find them all and put them in a list) and them take element out of that data (slower, because of obvious reasons.) Now, that doesn't mean you shouldn't have a method to return all your attributes at once (there are situations in which this is useful too), but you should have methods to individually access you attributes as well. It's just good programing, not specific to C++ or any other language.

Sign up to request clarification or add additional context in comments.

2 Comments

What do you think of the comments on the original post? Can you directly access attributes in C++ with the "class.attribute" or "object.attribute" style?
You absolutely can, but it's generally considered bad programming practice to directly access attributes. Again, this comes from C++, where member variables and functions are defined as public and private. This post explains it much better than I can: softwareengineering.stackexchange.com/questions/143736/…

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.