2

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?

tchuncly
  • 29
  • 5
  • 1
    Why would `V` be static if it is using the `m` and `k` members? – Vaughn Cato Jan 12 '14 at 15:00
  • @VaughnCato because I don't need nor want to pass `self` to it. I could then create a `class Model` in which I define `m` and `k` as class (not instance) variables. This does seem a bit weird to me, which is why I was reluctant enough to come here and ask whether this is the right way to do it...but it works. – tchuncly Jan 12 '14 at 19:39

2 Answers2

2

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.

Jonas Schäfer
  • 20,140
  • 5
  • 55
  • 69
  • Thanks, that indeed is one way out of this problem, and it is also going to be useful somewhere else in my project! I must confess that I still don't like the aesthetics of it (having to pass the parameters to every function in my_model.py), that's why I was focusing on finding a way to pass them once (as class arguments) but I can live with it. – tchuncly Jan 12 '14 at 16:11
2

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.

RemcoGerlich
  • 30,470
  • 6
  • 61
  • 79