3

I am seeking for a confirmation if my thinking is correct in terms of Python method vs function:

A method is a part of a class.

A function is defined outside of a class.

so e.g.

class FooBar(object):
    def __init__(self):
        pass
    def foo(self):
        pass


def bar():
    pass


if __name__ == '__main__':
    fb = FooBar()

I understand def foo defines method and def bar defines function. Am I correct?

E. Ducateme
  • 3,007
  • 2
  • 15
  • 28
darkman
  • 1,714
  • 1
  • 11
  • 34

2 Answers2

5

Yes. To be clear, methods are functions, they are simply attached to the class, and when that function is called from an instance it gets that instance passed implicitly as the first argument automagically*. It doesn't actually matter where that function is defined. Consider:

class FooBar:
    def __init__(self, n):
        self.n = n
    def foo(self):
        return '|'.join(self.n*['foo'])


fb = FooBar(2)

print(fb.foo())

def bar(self):
    return '*'.join(self.n*['bar'])

print(bar(fb))

FooBar.bar = bar

print(fb.bar())

*I highly recommend reading the descriptor HOWTO. Spoiler alert, Functions are descriptors. This is how Python magically passes instances to methods (that is, all function objects are descriptors who's __get__ method passes the instance as the first argument to the function itself when accessed by an instance on a class!. The HOWTO shows Python implementations of all of these things, including how you could implement property in pure Python!

juanpa.arrivillaga
  • 65,257
  • 7
  • 88
  • 122
2

Actually, methods and functions in Python are exactly the same thing!

It matters not one bit where it is defined. What matters is how it is looked up.

def defined_outside(*args):
    return args

class C:

    def defined_inside(*args):
        return args

C.defined_outside = defined_outside
defined_inside = C.defined_inside

instance = C()

print(         defined_inside (1,2))
print(         defined_outside(1,2))
print(instance.defined_inside (1,2))
print(instance.defined_outside(1,2))

which gives the output

(1, 2)
(1, 2)
(<__main__.C object at 0x7f0c80d417f0>, 1, 2)
(<__main__.C object at 0x7f0c80d417f0>, 1, 2)

(This will only work in Python 3: Two of these will produce a TypeError in Python 2.)

What is important to notice about the output is that, in the first two cases, the functions receive two arguments: 1 and 2. In the last two cases they receive three arguments: instance, 1 and 2.

In the cases where instance is passed to the function, the function is behaving like a method. In the cases where instance is not passed in, the function is behaving like a plain function. But notice that both behaviours are exhibited by both the function which was defined inside the classe and the one which was defined outside the class.

What matters is how the function was looked up. If it was looked up as an attribute of an instance of a class, then the function behaves like a method; otherwise it behaves like a free function.

[Incidentally, this binding behaviour only works for pure Python functions; it does not work for functions defined using the Python/C API. The latter always behave like functions and never like methods:

C.dir = dir
instance.dir()

will give you a directory of the global scope, not of instance, indicating that dir recived zero arguments, rather that receiving instance as an argument. ]

jacg
  • 1,728
  • 10
  • 21