How to efficiently develop a class containing related member variables?

Suppose I want a class called Num that contains a number, its half, and square.

I should be able to modify any of the three variables, and this will affect all member variables associated with it. I should be able to instantiate a class with any of three values.

What is the best way to design this class so that it can be easily modified and so that I don't leave anything behind?

Should I store all three numbers or just store the main number?

For example, here is how I will use my class in Python:

num = Num(5) print num.n, num.half, num.square 

And that should print 5, 2.5 and 25

It is simple, but I also want to initialize half of it.

 num = Num(half=2.5) print num.n, num.half, num.square 

And it should also print 5, 2.5 and 25

How can I make the init function know that it is half?

And I also want to change any number, and it will change all the associated numbers! For instance:

 num.square = 100 print num.n, num.half, num.square 

And that should print 10, 5 and 100.

How can I design a class?

+5
source share
3 answers

Same solution as @Daniel - extended, without lambda, Python 3.3:

 class Num: #class Num(object): for Python 2. def __init__(self, n = None, half = None, square = None): if n is not None: self.n = n elif half is not None: self.half = half elif square is not None: self.square = square else: self.n = 0 @property def n(self): return self.__n @n.setter def n(self, n): self.__n = n @property def half(self): return self.n / 2.0 @half.setter def half(self, n): self.n = n * 2 @property def square(self): return self.n ** 2 @square.setter def square(self, n): self.n = n ** .5 >>> five = Num(n=5) >>> five.half, five.n, five.square, five._Num__n (2.5, 5, 25, 5) >>> 
+4
source

You need properties to set or get any of your values. Different __init__ behavior can be achieved using keyword arguments:

 class Num(object): def __init__(self, n=None, half=None, square=None): self._n = 0 if n is not None: self.n = n if half is not None: self.half = half if square is not None: self.square = square @property def n(self): return self._n @n.setter def n(self, n): self._n = n @property def half(self): return self._n * 0.5 @half.setter def half(self, n): self._n = n * 2 @property def square(self): return self._n ** 2 @square.setter def square(self, n): self._n = n ** 0.5 n = Num(square=100) print n.half 

EDIT: now without lambdas, gives a good default value when the value is not given during initialization and does not throw an AttributeError otherwise.

+4
source

For another approach, you can apply the logic in __setattr__ :

 class Num(object): def __init__(self, n=None, half=None, square=None): if all(arg is None for arg in (n, half, square)): raise ValueError("Must supply at least one arg.") if n is not None: self.n = n elif half is not None: self.half = half elif square is not None: self.square = square def __setattr__(self, key, value): dct = self.__dict__ if key == "n": dct[key] = value dct["half"] = value / 2. dct["square"] = value ** 2 elif key == "half": dct[key] = value dct["n"] = value * 2 dct["square"] = self.n ** 2 elif key == "square": dct[key] = value dct["n"] = value ** .5 dct["half"] = self.n / 2. else: dct[key] = value 
+1
source

All Articles