-1

I couldn't figure out why I'm getting a NameError when trying to access a function inside the class.

This is the code I am having a problem with. Am I missing something?

class ArmstrongNumber:

    def cubesum(num):
        return sum([int(i)**3 for i in list(str(num))])

    def PrintArmstrong(num):
        if cubesum(num) == num:
            return "Armstrong Number"
        return "Not an Armstrong Number"

    def Armstrong(num):
        if cubesum(num) == num:
            return True
        return False

[i for i in range(1000) if ArmstrongNumber.Armstrong(i)] # this return NameError

Error-message:

NameError                                 Traceback (most recent call last)
<ipython-input-32-f3d39f24a48c> in <module>
----> 1 ArmstrongNumber.Armstrong(153)

<ipython-input-31-fd21586166ed> in Armstrong(num)
     10 
     11     def Armstrong(num):
---> 12         if cubesum(num) == num:
     13             return True
     14         return False

NameError: name 'cubesum' is not defined
piet.t
  • 11,400
  • 21
  • 42
  • 50
Rakesh
  • 463
  • 3
  • 13
  • @VaibhavVishal What is `this`? – Selcuk Feb 06 '19 at 06:45
  • 1
    You should decorate `cubesum` as `@staticmethod` and then use `ArmstrongNumber.cubesum(...)`. That being said, your class doesn't make much sense. – Selcuk Feb 06 '19 at 06:46
  • maybe he mentioned `self` – Jeril Feb 06 '19 at 06:46
  • yeah i meant `self`, sorry my mind was in javascript mode – Vaibhav Vishal Feb 06 '19 at 06:47
  • @Jeril Again, what is `self`? It is not a magical variable in Python unlike other languages. You have to specifically include it in the method signature. These are all static or class methods – Selcuk Feb 06 '19 at 06:48
  • he needs to create an object of the class before calling its methods, then `self` will work – Vaibhav Vishal Feb 06 '19 at 06:48
  • @VaibhavVishal I recommend you to read [this](https://stackoverflow.com/questions/2709821/what-is-the-purpose-of-self) question. – Selcuk Feb 06 '19 at 06:50
  • @Selcuk I would really appreciate if you can correct where I could improve? – Rakesh Feb 06 '19 at 06:51
  • Please also extract a [mcve] from your code before asking any question here at all, most of your code is useless for demonstration purposes. – Ulrich Eckhardt Feb 06 '19 at 06:52
  • 3
    @Rakesh There is no point using a class here as you are not keeping any state in it. Your class is just a collection of static functions, which can also be written as unbound (i.e. outside any class) methods. – Selcuk Feb 06 '19 at 06:52
  • @Selcuk Got it. It seems I have to learn more about classes in python. – Rakesh Feb 06 '19 at 06:58
  • I recommend reading a tutorial about OOP in Python. – TigerhawkT3 Feb 06 '19 at 06:58
  • @Selcuk. these are not static or classmethod s. these are std methods unexpectedly referring to the instance with *num* instead of *self* – JL Peyret Feb 06 '19 at 07:07
  • @JLPeyret Not quite. `num` is not an instance, it is an `int`. – Selcuk Feb 06 '19 at 07:08

2 Answers2

2

Use classname before method:

class ArmstrongNumber:

    def cubesum(num):
        return sum([int(i)**3 for i in list(str(num))])

    def PrintArmstrong(num):
        if ArmstrongNumber.cubesum(num) == num:
            return "Armstrong Number"
        return "Not an Armstrong Number"

    def Armstrong(num):
        if ArmstrongNumber.cubesum(num) == num:
            return True
        return False

print([i for i in range(1000) if ArmstrongNumber.Armstrong(i)])

Unlsess you pass self to the functions those functions are not instance methods. Even if you define that within class you still need to access them using classname.

Sociopath
  • 12,395
  • 17
  • 43
  • 69
  • 1
    @AkshayNevrekar Correction: They **are** class methods (or static methods, depending on the decorator used). What you probably wanted to mean is that they are **not** instance methods. – Selcuk Feb 06 '19 at 06:53
  • 1
    If you do it like this then there is no point in using class for this case, best would be just use static methods – Nihal Feb 06 '19 at 06:55
0

this should be your actual solution if you really want to use class

class ArmstrongNumber(object):

    def cubesum(self, num):
        return sum([int(i)**3 for i in list(str(num))])

    def PrintArmstrong(self, num):
        if self.cubesum(num) == num:
            return "Armstrong Number"
        return "Not an Armstrong Number"

    def Armstrong(self, num):
        if self.cubesum(num) == num:
            return True
        return False


a = ArmstrongNumber()

print([i for i in range(1000) if a.Armstrong(i)])

output

[0, 1, 153, 370, 371, 407]

2nd method:

if you dont want to use class then use static methods like this

def cubesum(num):
    return sum([int(i)**3 for i in list(str(num))])


def PrintArmstrong(num):
    if cubesum(num) == num:
        return "Armstrong Number"
    return "Not an Armstrong Number"


def Armstrong(num):
    if cubesum(num) == num:
        return True
    return False


# a = ArmstrongNumber()

print([i for i in range(1000) if Armstrong(i)])
Nihal
  • 5,106
  • 7
  • 23
  • 38
  • 1
    This is still pointless. Maybe move `num` into an `__init__` method then have methods like `.is_armstrong_number()`? – Selcuk Feb 06 '19 at 07:07