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)

Recommended Answers

All 11 Replies

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)

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!

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)

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

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.

"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")

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)

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.

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)
commented: Exactly what I needed. Rather than simply showing the code you explained the mechanical issue at hand. Great post! +2

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()?

Member Avatar for Enalicho
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)
              [B]3 CALL_FUNCTION            0[/B]
              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

commented: Thank you, especially for explaining the throw-away instance +2
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.