954,515 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Class help

I'm trying to understand utilizing classes and their methods. I made a simple program to exit or print 'Will continue' given a word. however I keep getting a TypeError for self and through reading my books and searching online I'm still not quite sure why. the code is:

class OffSwitch(object):
    def __init__(self):
        self.keycheck='off'

    def turnOff(self,key):
        if key==self.keycheck:
            SystemExit
        else:
            print('will continue')


switchword=input('Enter a word: ')

OffSwitch.turnOff(switchword)


and getting the error

Traceback (most recent call last):
  File "E:/classpractice", line 14, in <module>
    OffSwitch.turnOff(switchword)
TypeError: turnOff() takes exactly 2 arguments (1 given)
pyguy62
Posting Whiz
353 posts since Aug 2011
Reputation Points: 34
Solved Threads: 19
 

I'm not so great at explaining all the nuts and bolts of classes, and probably have some bad habits, but I've fixed your code so that it at least works:

class OffSwitch:
    def __init__(self):
        self.keycheck='off'

    def turnOff(self, key):
	print key, 'hi'
        if key==self.keycheck:
            SystemExit
        else:
            print('will continue')


switchword=str(raw_input('Enter a word: ') )

foo=OffSwitch()
foo.turnOff(switchword)


First, I changed your class declaration to class Offswitch: instead of Offswitch(object). I don't know why you need to put the object there, maybe there's a good reason, but it's not necessary.

Second, I changed your switchword call so that it knew to make your input a string. Again, your syntax may be fine, but this is how I do it.

Lastly, and importantly, the code works when you initialize the class before calling its methods. I made a class instance by using:

foo=OffSwitch()


Now, the variable foo, is the instance of your class. Basically, foo is a variable just waiting around for you to run the class methods. I'm no expert, but I think you always need to first instatiate a class like this before you run its methods. To run methods, the syntax is:

foo.turnOff(switchword)
shoemoodoshaloo
Junior Poster
168 posts since May 2009
Reputation Points: 16
Solved Threads: 6
 

I'm not so great at explaining all the nuts and bolts of classes, and probably have some bad habits, but I've fixed your code so that it at least works:

class OffSwitch:
    def __init__(self):
        self.keycheck='off'

    def turnOff(self, key):
	print key, 'hi'
        if key==self.keycheck:
            SystemExit
        else:
            print('will continue')


switchword=str(raw_input('Enter a word: ') )

foo=OffSwitch()
foo.turnOff(switchword)

First, I changed your class declaration to class Offswitch: instead of Offswitch(object). I don't know why you need to put the object there, maybe there's a good reason, but it's not necessary.

Second, I changed your switchword call so that it knew to make your input a string. Again, your syntax may be fine, but this is how I do it.

Lastly, and importantly, the code works when you initialize the class before calling its methods. I made a class instance by using:

foo=OffSwitch()

Now, the variable foo, is the instance of your class. Basically, foo is a variable just waiting around for you to run the class methods. I'm no expert, but I think you always need to first instatiate a class like this before you run its methods. To run methods, the syntax is:

foo.turnOff(switchword)

Thank you. I'm using Python3 so the raw_input wouldn't work but that's fine. The big part for me was the foo variable, can anybody confirm for sure that you must instantiate before running methods for me? I just want to be sure for future reference. Again, thank you Shoemoodoshaloo!

pyguy62
Posting Whiz
353 posts since Aug 2011
Reputation Points: 34
Solved Threads: 19
 

I would do something like:

class Switch(object):
    def __init__(self, on=True):
        self.on = on
        self.off_word = 'off'

    def turn_off(self, key):
        self.on = key!=self.off_word

    def __str__(self):
        return "Switch(on=%s)" % self.on

myswitch = Switch()

while myswitch.on:
    myswitch.turn_off(input('Enter a word: '))
    print(myswitch)
pyTony
pyMod
Moderator
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852
 

okay so a similar issue I'm having related to the matter within a class I have the method

def takeDamage(self):
        self.hp=self
        amount=Enemy.attackpower
        self.hp-=amount
        return self.hp


However when I try to have the Class Enemy send a message 'Starship.takeDamage()' I recieve a TypeError noting that take.Damage takes 1 argument and I am supplying it none, I thought that self was automatically ignored...no? Sorry, I'm still trying to understand OOP

pyguy62
Posting Whiz
353 posts since Aug 2011
Reputation Points: 34
Solved Threads: 19
 

Line two does not make sense, because of line 4 and it also makes instanses' methods strangely available as methods' attribute. Also the line 4 should not work then if you need the original hp value. It is in most cases not what you actually need to do to use attributes of class like in line 5. Usually the attributes should be defined in __init__ method of the class to catch this kind of errors and then you can have more than one instance of class. Mostly you are also not returning values in methods as the results are updated attributes. Your code should have lots of references of self.something or parameter.something not Class.something. Try to understand the way I did in the code I posted in response to your earlier code in the other thread.

pyTony
pyMod
Moderator
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852
 


"self" is just a reference to the class, so that the class knows that the function or variable is in it's name space, so you have to include it when calling a function of the class from/within the class, otherwise the compiler will default to looking outside of the class for the function or variable.

class OffSwitch(object):
    def __init__(self):
        self.keycheck='off'
        print self.keycheck

        self.turn_off('yellow')   
  
    def turn_off(self,key):
        self.keycheck = key
        print self.keycheck
     
OS = OffSwitch()
#
# outside the class
OS.turn_off("outside")
woooee
Nearly a Posting Maven
2,454 posts since Dec 2006
Reputation Points: 777
Solved Threads: 714
 

This would fix it, but I would rather go with a formal instance ...

class OffSwitch(object):
    def __init__(self):
        self.keycheck='off'

    def turnOff(self,key):
        if key==self.keycheck:
            SystemExit
        else:
            print('will continue')


switchword=input('Enter a word: ')

OffSwitch().turnOff(switchword)
vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

Okay, here's a MUCH better example of the issue I'm having, working with instances instead of class attributes.

class Person(object):
    def __init__(self, name, health=100):
        self.name=name
        self.health=100
    def hurt(self, amount):
        self.health-=amount
        print(self.health)

class Killer(object):
    def __init__(self):
        import random
        power= random.randint(10, 21)
        self.power=power
        
    def stab(self,Person):
        Person.hurt(self.power)

James=Person('James')
Killer.stab(James)


Killer.stab(James) recieves a TypeError because "stab" takes 2 arguments and only James is given. I thought that the self argument would be ignored...I guess I'm very much missing something important here...Also, I'm just using print to see if it works, I wouldn't normally use it there.

pyguy62
Posting Whiz
353 posts since Aug 2011
Reputation Points: 34
Solved Threads: 19
 


A class does not exist, it is a prototype for actual objects. Only a class instance exists. That is why we declare an instance for each class object desired.

class Person(object):
    def __init__(self, name, health=100):
        self.name=name
        self.health=100

    def hurt(self, amount):
        print("%s health = %d - %d" % (self.name, self.health, amount))
        self.health-=amount
     
class Killer(object):
    def __init__(self):
        import random
        power= random.randint(10, 21)
        self.power=power
        print("power:", self.power)
     
    def stab(self,Person):
        Person.hurt(self.power)
     
K = Killer()
James=Person('James')
Karen=Person('Karen')
K.stab(James)
K.stab(Karen)
K.stab(James)
woooee
Nearly a Posting Maven
2,454 posts since Dec 2006
Reputation Points: 777
Solved Threads: 714
 

Ohhhh so my issue was that I was trying to call nothingness, I needed to define an instance of the class? i.e. K=Killer()?

pyguy62
Posting Whiz
353 posts since Aug 2011
Reputation Points: 34
Solved Threads: 19
 
import random

class Person(object):
    
    def __init__(self, name, health=100):
        self.name = name
        self.health = 100
        
    def hurt(self, amount):
        self.health -= amount
        print self.health

    def __str__(self):
        return repr('My name is {name} and my health is {health}'.format(name=self.name, health=self.health))
    

class Killer(Person):
    
    def __init__(self, name, health=100):
        Person.__init__(self,name, health)
        power = random.randint(10, 21)
        self.power = power
        
    def stab(self,reciever):
        reciever.hurt(self.power)

        
if __name__ == '__main__':
    stabee = Person('James')
    staber = Killer('Henry')
    print stabee
    print staber
    staber.stab(stabee)
    print stabee
    print staber


Here's my take on it.
Killer inherits from Person, as a Killer is a type of Person.

The problem you were getting was from using an instance of a class.

Killer.stab(James)

This doesn't do what you think it does. It has no instance to work with, so there is no "self" to play with. It doesn't create an instance, so the methods can't be called without supplying an instance to work on.

Killer().stab(James)

On the other hand creates an instance of Killer, albeit a throw-away, and uses method stab.


This is show when I use dis -

def a():
    Killer().stab(James)

def b():
    Killer.stab(James)

dis.dis(a)
dis.dis(b)

Which gives

60           0 LOAD_GLOBAL              0 (Killer)
              <strong>3 CALL_FUNCTION            0</strong>
              6 LOAD_ATTR                1 (stab)
              9 LOAD_GLOBAL              2 (James)
             12 CALL_FUNCTION            1
             15 POP_TOP             
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

 63           0 LOAD_GLOBAL              0 (Killer)
              3 LOAD_ATTR                1 (stab)
              6 LOAD_GLOBAL              2 (James)
              9 CALL_FUNCTION            1
             12 POP_TOP             
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE

I've highlighted the important line.
HTH

Enalicho
Junior Poster in Training
62 posts since Aug 2011
Reputation Points: 28
Solved Threads: 13
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You
View similar articles that have also been tagged: