0

I'm new to programming and can't quite grasp the formalism of classes. I have a file plots.py consisting of a class of functions:

import numpy as np

class SHO1D:
    def prob(T, x, N):
        i = x+1
        product = 1
        while i <= N:
            product *= (1 - np.exp(-1/T)**i)
            i += 1
        return np.exp(-1/T)**x * product

    def bec(T, N):
        n_0 = 0.
        for x in range(N + 1):
            n_0 += SHO1D.prob(T, x, N) * x
        return n_0

I'm successfully importing this class in another file as follows:

from plots import SHO1D

N = 100
temps = np.logspace(1,1.45,num=300)
plt.plot(temps, SHO1D.bec(temps, N))

However, I've read in a number of posts that, when calling functions within a class, I shouldn't prefix my functions with their class name as I did above. Rather, I should make use of self. I've not been able to modify my program above to make use of this feature without redefining my function bec to include a third argument "self" in addition to "T" and "N", which I would like to avoid because I want to be able to plot those functions. As such, I would appreciate an explanation as to how this feature should be implemented in my case.

Daphne
  • 165
  • 4
  • This series of videos about classes and objects helped me out a lot when I was confused about the same thing, check it out: https://www.youtube.com/watch?v=8yjkWGRlUmY – JaniniRami Aug 20 '20 at 23:20
  • 8
    Your class shouldn't be a class if you aren't using internal state, it should just be a module with functions. – juanpa.arrivillaga Aug 20 '20 at 23:22
  • @juanpa.arrivillaga unless the rest of his/her file was huge and she/he just wanted to group the functions in a meaningful way. Assuming all of his/her functions are magically related to the module/file. – theX Aug 20 '20 at 23:41
  • I wanted to use classes as a way to categorize different sets of functions, e.g. I would like to have a number of classes each with a function "prob" or "bec" (that describe the same thing but under different conditions). I think this could save me from possible confusion later on if I were to instead assign a unique name to each individual function, especially if I'd like to reuse some functions from other classes in the file. Perhaps there is a better way to do this than with the use of classes. – Daphne Aug 20 '20 at 23:52
  • 1
    @theX that's not a good reason to use a class. You can just split your modules up. – juanpa.arrivillaga Aug 21 '20 at 00:03
  • 1
    @Daphne that is fundamentally not what a class is for. – juanpa.arrivillaga Aug 21 '20 at 00:03

2 Answers2

0

self is used a lot when using classes. To use it, put it as the first parameter in your function (which is inside the class). When calling the function (class().function()), the self parameter would be autofilled by Python, so you only need to fill in the original parameters. Local variables are variables defined inside a function that can't be reached after the function is called (unless the variable is returned). self is a property of the class. If it's changed by a function inside the same class, it is saved. Think of it as a dictionary passed in as an argument: self.property

You should find variables inside the functions that you would like to save and be able to use in other functions (in the same class).

I also suggest you put some comments in your code, because right now I'm not getting anything out of your code (If I did, I might be able to suggest what to turn into properties of the self).


class SHO1D():
    def prob(self, T, x, N):
        i = x+1
        product = 1
        while i <= N:
            product *= (1 - np.exp(-1/T)**i)
            i += 1
        return np.exp(-1/T)**x * product

    def bec(self, T, N):
        n_0 = 0
        for x in range(N + 1):
            n_0 += self.prob(T, x, N) * x
        return n_0
0

First, please follow Python code style guide (aka PEP8), it's necessary for understanding your code in future.

About your implementation:

By default, Python uses self as the first argument for all functions in a class (when functions are not decorated with @classmethod or @staticmethod, about decorators, classmethod and staticmethod for beginners).

So in your case, in all functions, T it's an object of your class. But for this statement, you need to create a class instance (all about classes).

You have a few ways to resolve a problem:

  1. Create an instance of the class and use self.

For example:

class SHO1D:
    def __init__(self, T):
        self.T = T

    def prob(self, x, N):
        i = x+1
        product = 1
        while i <= N:
            product *= (1 - np.exp(-1/self.T)**i)
            i += 1
        return np.exp(-1/self.T)**x * product

    def bec(self, N):
        n_0 = 0.
        for x in range(N + 1):
            n_0 += self.prob(x, N) * x
        return n_0

And:

from plots import SHO1D

N = 100
temps = np.logspace(1,1.45,num=300)
sho1d_temps = SHO1D(temps)
plt.plot(temps, sho1d_temps.bec(N))
  1. Decorate methods using @classmethod:
class SHO1D:
    @classmethod
    def prob(cls, T, x, N):
        i = x+1
        product = 1
        while i <= N:
            product *= (1 - np.exp(-1/T)**i)
            i += 1
        return np.exp(-1/T)**x * product

    @classmethod
    def bec(cls, T, N):
        n_0 = 0.
        for x in range(N + 1):
            n_0 += cls.prob(T, x, N) * x
        return n_0

The second part does not need to be changed.

Dmytro Hoi
  • 141
  • 6