user1586038
user1586038

Reputation: 79

Python rookie: Headaches with Object Oriented Programming

  1. What is the difference between these two class declarations? What does "object" do?

    class className(object):
        pass 
    
    class className:
        pass 
    
  2. Why do I get this error when I run the below code: "Takes no arguments (1 given)"

    class Hobbs():
        def represent():
            print "Hobbs represent!"
        represent = classmethod(represent)
    
    Hobbs.represent()   
    
  3. Why does "Foo.class_foo()" give no error even though I did not pass an argument to the function.

    class Foo(object):
        @staticmethod
        def static_foo():
        print "static method"
        @classmethod
        def class_foo(cls):
            print "Class method. Automatically passed the class: %s" % cls      
    Foo.static_foo()
    Foo.class_foo()
    
  4. Why do I get this error when I run the below code?

    class Foo(object):  
        def static_foo():
            print "static method"
            static_foo = staticmethod(static_foo)
        def class_foo(cls):
                print "Class method. Automatically passed the class: %s" % cls
        class_foo = classmethod(class_foo)  
    Foo.static_foo()
    Foo.class_foo()
    

"TypeError: unbound method static_foo() must be called with Foo instance as first argument (got nothing instead)"

Upvotes: 1

Views: 364

Answers (5)

Peter Sobot
Peter Sobot

Reputation: 2557

  1. Using object as the base class for new classes has been convention since at least Python 2.2, and is called "New-Style Classes" - see this question for more details. Old style classes (i.e.: ones that don't inherit from object) are set to be deprecated in Python 3.0. The reasons for these changes are somewhat obscure, and have to do with low-level class resolution and inheritance patterns.

  2. Python instance methods, by convention, take self as their first argument. This argument is passed implicitly - so if your method definition doesn't take self, then the interpreter will complain that the method you're trying to call doesn't accept the argument that's being automatically passed to it. This works exactly the same for classmethods, only instead of taking self, they usually take cls. (Just a naming convention.) A quick fix:

    class Hobbs():
        def represent(cls):
            print "Hobbs represent!"
        represent = classmethod(represent)
    
    Hobbs.represent()   
    
  3. Calling Foo.class_foo() doesn't cause any issues, as Python automatically passes the class object to the class_foo method whenever you call it. These methods are called bound methods - meaning that they are regular functions, but bound to a class or instance object. Bound methods automatically take the class or instance object that they're bound to as their first argument.

  4. Indentation level matters in Python. I've tried executing the code sample you've provided, but both the static_foo = and class_foo = lines must be within the Foo class definition, rather than below it or within other methods. When indented properly, the code runs fine:

    class Foo(object):
        def static_foo():
            print "static method"
        static_foo = staticmethod(static_foo)
        def class_foo(cls):
            print "Class method. Automatically passed the class: %s" % cls
        class_foo = classmethod(class_foo)
    Foo.static_foo()
    Foo.class_foo()
    

Upvotes: 5

lvc
lvc

Reputation: 35059

  1. The last two are identical - empty brackets is the same as omitting them. The first inherits from the builtin class object, making it a "new style class". The reason for new and old style classes is historical, and old-style are only kept around for backward compatibility - essentially, in Python 2, the advice is to always inherit from object if you don't inherit from anything else, because some of the fancy tricks you will learn eventually rely on it. If you upgrade to Python 3, this becomes the default behaviour, and all three class declarations are equivalent.

  2. A classmethod needs to take a first argument similar to self - when you call Hobbs.represent(), Python end up passing Hobbs in as that first argument. This is the fundamental difference between classmethod and staticmethod - a classmethod takes a first argument (being the class it was called on), a staticmethod doesn't.

  3. Same as 2 - class is passed in to the classmethod in place of the usual self.

  4. This one appears to be an indentation issue - your code works as written if it is indented as:

    def static_foo():
        print "static method"
    static_foo = staticmethod(staticfoo)
    

but not as

def static_foo():
    print "static method"
    static_foo = staticmethod(staticfoo)    

Because the line reassigning static_foo needs to be in the class body, not part of the function itself. In the latter, that line isn't executed until the function is run (which means it isn't run, since the function errors) - and it assigns a staticmethod to a local variable rather than to the method itself. This type of error is one of the reasons it is good to use the decorator syntax:

 class Hobbs:
    @staticmethod
    def static_foo():
         print "static method"

works.

Upvotes: 1

Samy Arous
Samy Arous

Reputation: 6814

  1. class ClassName(OtherClass): means that ClassName inherits from OtherClass. inheritance is a big subject but basically it means that ClassName has at least the same functions and fields as OtherClass.

    In python, Everything is an object and therefor, all classes inherit implicitely or explicitely from object. This being said

    the class ClassName(): declaration is an old syntax and should be avoided.

    class ClassName: is equivalent to class ClassName(object):

  2. A class method is not a static method. It is like any other instance method except it is passed the class as parameter rather than the instance.

    Your class method declaration is wrong. It should have a cls parameter.

  3. A static method in the other hand, is a method that is called out of context. Meaning it has no relation with any instance. It can be thought of as a independent function that is simply put in a class for semantic reasons.

    This is why it does not require a self parameter and one is never passed to it.

  4. You have an indentation error. That might be causing the error.

Upvotes: 0

Keith
Keith

Reputation: 43024

Most of your questions aren't really about object orientation per se, but Python's specific implementation of it.

  1. Python 2.x has undergone some evolution, with new features being added. So there are two ways to define classes, resulting in a "new-style class", and and "old-style class". Python 3.x has only "new style class". The base object of new-style classes is called object. If you inherit from that you have a new-style class. It gives you some of the extra features such as certain decorators. If you have a bare (no inheritance) definition in Python 2.x you have an old-style class. This exists for backwards compatibility. In Python 3.x you will also get a new-style class (so inheriting from object is optional there).

  2. You have made represent() and "class method". So it will get the class object as implicit first argument when it is called. But those only work with new-style classes. you have tried to use it with an old-style class. So it won't work.

  3. Python automatically inserts the class object as argument zero for a class method. So that is the correct pattern and it works.

  4. the method somehow didn't get make into a class method, maybe because the indentation is wrong.

Upvotes: 0

Joran Beasley
Joran Beasley

Reputation: 113940

all class functions must take self as the first argument

class  A:
   def my_func(self):
        print "In my func"

static methods are classes that are pretty much just a function in a namespace (and are rarely used in python)

class methods are functions in the class namespace that should be called on the class itself rather than an instance

Upvotes: 0

Related Questions