tchuncly
tchuncly

Reputation: 29

Python structuring - Do I really need a class?

I have a problem to which the solution seems to be creating a class. However, all the methods in this class would be static, and I would only instantiate the class once, so I wonder if using a class is the right way to go.

More specifically, I want to have a separate module to store some functions and some variables that are essentially the skeleton of the program. These functions and variables depend on some parameters that define my model (and I do not want to pass these parameters as arguments for other reasons that I may specify later if relevant). Ex.:

# my_model.py
def V(x):
   return -m*x**2 + k*x**4

On the other module I do a scan over some values of these parameters "m" and "k", and for each of these values I want to, say, find the minimum of V:

# scan.py
from scipy.optimize import minimize
import random, my_model

for i in range(5):
   m = random.randint(0,10)
   k = random.randint(0,10)
   minimize(my_model.V, 0)

Of course, this won't work, because my_model.V has no clue as to what m and k are. As I said, I thought about creating a class in the my_model file, defining the function V (and others!) inside that class, and instantiate the class in scan.py passing the parameters "m", "k" as arguments. But, as I said, this sounds to me as an overuse of the class feature. For instance, clearly the function V above would be static, and so would happen with ALL other definitions in this class. So is there any other, more proper way of achieving what I want, or am I just "over-reacting" and/or completely misunderstanding the use of classes in Python?

Upvotes: 2

Views: 102

Answers (2)

Jonas Schäfer
Jonas Schäfer

Reputation: 20718

You can use functools.partial:

# my_model.py
def V(m, k, x):
   return -m*x**2 + k*x**4

And use it like this:

# scan.py
import functools
from scipy.optimize import minimize
import random, my_model

for i in range(5):
    m = random.randint(0,10)
    k = random.randint(0,10)
    minimize(functools.partial(my_model.V, m, k), 0)

This is only really meant as an alternative to a class. The tastes differ here, some people suggest that you really should do it that way. Using a class and having @classmethods for the different model functions would be fine for me too.

Upvotes: 2

RemcoGerlich
RemcoGerlich

Reputation: 31250

I'm not sure I'm understanding your problem correctly, but I think what I would do is:

1) Make m and k parameters of V

def V(x, m, k):
    return -m*x**2 + k*x**4

2) The moment you want to minimize V regarding x, for a fixed m and k, create a partial function that has m and k already set, and minimize that:

from functools import partial

for i in range(5):
     m = random.randint(0, 10)
     k = random.randint(0, 10)
     V_with_fixed_m_k = partial(V, m=m, k=k)
     minimize(V_with_fixed_m_k, 0)

Alternatively, make a function that returns a version of V that uses the right m and k:

def parameterized_V(m, k):
    def V(x):
        return -m*x**2 + k*x**4
    return V

But that's basically a reimplementation of functools.partial only for V.

Upvotes: 2

Related Questions