Fomalhaut
Fomalhaut

Reputation: 9795

How to get and set data attributes of a class?

I want to implement 3D vector in Python that stores its components in a numpy array (or another container). And I want to access the components as x, y and z in order to get and set them. What is the best way to do it?

I implemented it like this:

import numpy as np

class Vector3d:
    components = ['x', 'y', 'z']

    def __init__(self):
        self._data = np.array([0.0, 0.0, 0.0])

    def __getattr__(self, key):
        if key in self.components:
            index = self.components.index(key)
            return self._data[index]
        else:
            return super().__getattr__(key)

    def __setattr__(self, key, value):
        if key in self.components:
            index = self.components.index(key)
            self._data[index] = value
        else:
            return super().__setattr__(key, value)

    def __repr__(self):
        return repr(self._data)

    def norm(self):
        return np.linalg.norm(self._data)

a = Vector3d()
a.x = 1.2
a.y = 2.3
a.z = 3.4
print(a.x, a.y, a.z)
print(a)
print(a.norm())

What I dislike in it. First, I duplicated the code if key in self.components: index = self.components.index(key). Second, searching for the index every time seems to be non-optimal towards the consuming time. I believe there's a better way to implement it. Please, suggest me your approaches.

I'm searching for a solution for Python 3.

Upvotes: 0

Views: 740

Answers (1)

Harsh
Harsh

Reputation: 399

Okay, the comment section seems constricting, so I'll move here...

Here is what I made out, ordered by priority:

  1. You do not like how if key in self.components is linearly searching for the component x (or others).
  2. You do not like that repeating piece of code.

Maybe this is something that can work:

import numpy as np

class Vector3d:
    components = {'x':0, 'y':1, 'z':2}

    def __init__(self):
        self._data = [0.0, 0.0, 0.0]

    def __getattr__(self, key):
        return self._data[components[key]] ###!!!

    def __setattr__(self, key, value):
        self._data[components[key]] = value ###!!!

    def __repr__(self):
        return repr(self._data)

    def norm(self):
        return np.linalg.norm(self._data)

a = Vector3d()
a.x = 1.2
a.y = 2.3
a.z = 3.4
print(a.x, a.y, a.z)
print(a)
print(a.norm())
  1. The search is now not linear, so it's a little more optimal than what you wrote.
  2. The multiple lines of repeating code is now gone, but that self._data[components[key]] is something we got to live with! :D

You can add a try and catch to access data from super() in case the return self._data[components[key]] fails!

Upvotes: 3

Related Questions