55

I'm doing Code Academy's tutorials on Python, and I'm a bit confused about the definition of method and function. From the tutorial:

You already know about some of the built-in functions we've used on (or to create) strings, such as .upper(), .lower(), str(), and len().

Coming from C++, I would think .upper() and .lower() would be called methods and len() and str() functions. In the tutorial, the terms seem to be used interchangeably.

Does Python distinguish between methods and functions in the way C++ does?

Unlike Difference between a method and a function, I'm asking about the particulars of Python. The terms 'method' and 'function' do not seem to always follow the definition given in the accepted answer of the linked question.

smci
  • 26,085
  • 16
  • 96
  • 138
Q-bertsuit
  • 2,655
  • 5
  • 22
  • 43
  • 10
    Not sure why this is still marked as a duplicate. The whole point of this question is that Python uses these terms differently than how they are explained in the duplicate answer. – Q-bertsuit May 16 '17 at 12:11
  • 1
    I'm voting to reopen since there's some good and interesting answers here, but I think the premise of your question is pretty weak. You're generalizing a pattern seen only in a third-party tutorial onto an entire community. If you could show the pattern occurs more widely it would be an interesting question, but otherwise it would be better directed at just the author of the tutorial. – glennsl Mar 29 '18 at 11:52
  • This question asked specifically for comparison of Python vs C++. Should never have been closed as dupe of [C++ question](https://stackoverflow.com/questions/155609/whats-the-difference-between-a-method-and-a-function). Perhaps of [How does the Python data model handle unbound methods, bound methods and function calls? What's the difference?](https://stackoverflow.com/questions/11949808/how-does-the-python-data-model-handle-unbound-methods-bound-methods-and-functio#comment90907615_11949808), or something else, or reopened. – smci Aug 23 '18 at 05:51
  • Yeah Code Academy is being sloppy with terminology. But still there are some differences, per Krumelur's answer. – smci Aug 24 '18 at 03:31

5 Answers5

55

Needs Attention: This answer seems to be outdated. Check this

A function is a callable object in Python, i.e. can be called using the call operator (though other objects can emulate a function by implementing __call__). For example:

>>> def a(): pass
>>> a
<function a at 0x107063aa0>
>>> type(a)
<type 'function'>

A method is a special class of function, one that can be bound or unbound.

>>> class A:
...   def a(self): pass
>>> A.a
<unbound method A.a>
>>> type(A.a)
<type 'instancemethod'>

>>> A().a
<bound method A.a of <__main__.A instance at 0x107070d88>>
>>> type(A().a)
<type 'instancemethod'>

Of course, an unbound method cannot be called (at least not directly without passing an instance as an argument):

>>> A.a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method a() must be called with A instance as first argument (got nothing instead)

In Python, in most cases, you won't notice the difference between a bound method, a function, or a callable object (i.e. an object that implements __call__), or a class constructor. They all look the same, they just have different naming conventions. Under the hood, the objects may look vastly different though.

This means that a bound method can be used as a function, this is one of the many small things that makes Python so powerful

>>> b = A().a
>>> b()

It also means that even though there is a fundamental difference between len(...) and str(...) (the latter is a type constructor), you won't notice the difference until you dig a little deeper:

>>> len
<built-in function len>
>>> str
<type 'str'>
Smart Manoj
  • 3,837
  • 2
  • 24
  • 45
Krumelur
  • 27,311
  • 6
  • 71
  • 108
  • 5
    I agree that method is a subset of function. I would not say that a function is any callable object. A class is callable but I wouldn't call it a function. – BrenBarn Jan 07 '14 at 21:06
  • 3
    Methods are functions that are associated with specific classes, right? – Barmar Jan 07 '14 at 21:07
  • 11
    A method is associated with a class, a *bound* method is associated with an instance of a class. – Krumelur Jan 07 '14 at 21:08
  • @BrenBarn True, I changed the wording. – Krumelur Jan 07 '14 at 21:09
  • As the error message in your last example, suggests, an unbound method can indeed be called. You just have to pass an instance as the first argument. – BrenBarn Jan 07 '14 at 21:10
  • 1
    @BrenBarn Well, that is actually true. And in Python 3 you could even pass any object as first argument, I think. – Krumelur Jan 07 '14 at 21:13
  • @BrenBran I don't agree that a method is a subset of function. A method is MORE than a fgunction, it pacvks a function and an instance, see the excerpt at the beginning of my answer - I agree tjhat a class must not be called a function. Otherwise, the results of ``type()`` are meaningless. – eyquem Jan 08 '14 at 00:43
  • @Krumelur I'm pretty sure that a bound method isn't associatd with an instance. A bound method knows of an instance, but is associated to a class, as an unbound method is (associated to a class). But an unbound method doesn't know of a particular instance. It's the same object in the two cases, but hasn't the same info inside it. See and critic my answer please, I describe these facts in details, as much as I understand them and I can explain. – eyquem Jan 08 '14 at 00:48
  • @eyquem Well, technically, the principal difference would be the value of the `im_self` attribute (which is `None` for unbound methods), I presume. – Krumelur Jan 08 '14 at 00:59
  • Yes it is None. It is easy to verify by printing ``A.a.im_self``. But I wouldn't say there are unbounds methods and bounds methods, relatively to a same given class. There is only one method object and the method is SAID unbound when im_self is None, and SAID bound when im_self is an instance. It doesn't exist unbounds and bounds methods independantly, they are called like this or that according the manner the call is done. – eyquem Jan 08 '14 at 01:32
  • They are the same object types, but I believe they are immutable (try setting im_self!), and different instances (`A.a is A().a == False`). Edit: actually, `A.a is A.a == False`. I did not expect this! – Krumelur Jan 08 '14 at 15:27
  • Which version it is? – Smart Manoj Oct 24 '20 at 15:44
  • Hope it is 2.x version – Smart Manoj Oct 24 '20 at 16:25
4

If you still don’t understand how methods work, a look at the implementation can perhaps clarify matters. When an instance attribute is referenced that isn’t a data attribute, its class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.

http://docs.python.org/2/tutorial/classes.html#method-objects

Read carefully this excerpt.

It means :

1) An instance doesn't really hold an object being a method that would be its attribute.
In fact, there is not at all a "method" attribute in the __dict__ of an instance (__dict__ is the namespace of an object)

2) The fact that an instance seems to have a "method" when a "method" attribute is called, is due to a process, not the presence of a method object inside the namespace of an instance

3) Also, there doesn't really exist a method object in the namespace of a class.

But there's a difference with an instance, because there must be somewhere something that leads to a real method object when such a call is done, must not ?

What is called a "method" attribute of a class, for easiness of wording, is in reality a function object being attribute in the namespace of the class.
That is to say, a pair (identifier of the function, function) is a member of the __dict__ of a class, and this attribute allows the intepreter to construct a method object when a method call is performed.

4) Again, the fact that a class seems to have a "method" when a "method" attribute is called, is due to a process, not to the presence of a method object inside the namespace of a class

EDIT I'm no more sure of that; see at the end

5) A method object (not "method" object; I mean the real object being really a method`, what is described in the excerpt) is created at the moment of the call, it doesn't exists before.
It is a kind of wrapper : it packs pointers to the instance object and the function object on which the method is based.

So, a method is based on a function. This function is for me the real attribute of the class holding the said "method", because this function really belongs to the namespace ( __dict__ ) of the class: this function is described as a <function ......> when the __dict__ is printed.
This function can be reached from the method object using the alias im_func or __func__ (see the below code)

.

I believe that these notions are not very commonly known and understood. But the following code proves what I said.

class A(object):
    def __init__(self,b=0):
        self.b = b
    print 'The __init__ object :\n',__init__

    def addu(self):
        self.b = self.b + 10
    print '\nThe addu object :\n',addu


print '\nThe A.__dict__  items :\n',
print '\n'.join('  {0:{align}11}  :  {1}'.format(*it,align='^')
                for it in A.__dict__.items())
a1 = A(101)
a2 = A(2002)

print '\nThe a1.__dict__  items:'
print '\n'.join('  {0:{align}11}  :  {1}'.format(*it,align='^')
                for it in a1.__dict__.items())

print '\nThe a2.__dict__  items:'
print '\n'.join('  {0:{align}11}  :  {1}'.format(*it,align='^')
                for it in a2.__dict__.items())

print '\nA.addu.__func__ :',A.addu.__func__
print id(A.addu.__func__),'==',hex(id(A.addu.__func__))
print

print 'A.addu :\n  ',
print A.addu,'\n  ',id(A.addu),'==',hex(id(A.addu))

print 'a1.addu :\n  ',
print a1.addu,'\n  ',id(a1.addu),'==',hex(id(a1.addu))
print 'a2.addu :\n  ',
print a2.addu,'\n  ',id(a2.addu),'==',hex(id(a2.addu))

a2.addu()
print '\na2.b ==',a2.b

print '\nThe A.__dict__  items :\n',
print '\n'.join('  {0:{align}11}  :  {1}'.format(*it,align='^')
                for it in A.__dict__.items())

result

The __init__ object :
<function __init__ at 0x011E54B0>

The addu object :
<function addu at 0x011E54F0>

The A.__dict__  items :
  __module__   :  __main__
     addu      :  <function addu at 0x011E54F0>
   __dict__    :  <attribute '__dict__' of 'A' objects>
  __weakref__  :  <attribute '__weakref__' of 'A' objects>
    __doc__    :  None
   __init__    :  <function __init__ at 0x011E54B0>

The a1.__dict__  items:
       b       :  101

The a2.__dict__  items:
       b       :  2002

A.addu.__func__ : <function addu at 0x011E54F0>
18765040 == 0x11e54f0

A.addu :
   <unbound method A.addu> 
   18668040 == 0x11cda08
a1.addu :
   <bound method A.addu of <__main__.A object at 0x00CAA850>> 
   18668040 == 0x11cda08
a2.addu :
   <bound method A.addu of <__main__.A object at 0x011E2B90>> 
   18668040 == 0x11cda08

a2.b == 2012

The A.__dict__  items :
  __module__   :  __main__
     addu      :  <function addu at 0x011E54F0>
   __dict__    :  <attribute '__dict__' of 'A' objects>
  __weakref__  :  <attribute '__weakref__' of 'A' objects>
    __doc__    :  None
   __init__    :  <function __init__ at 0x011E54B0>

.

EDIT

Something is troubling me and I don't know the deep innards of the subject:

The above code shows that A.addu , a1.addu and a2.addu are all the same method object, with a unique identity.
However A.addu is said an unbound method because it doesn't have any information concerning an particular instance,
and a1.addu and a2.addu are said bound methods because each one has information designating the instance that must be concerned by the operations of the method.
Logically, for me, that would mean that the method should be different for each of these 3 cases.

BUT the identity is the same for all three, and moreover this identity is different from the identity of the function on which the method is based.
It leads to the conclusion that the method is really an object living in the memory, and that it doesn't change from one call from an instance to another cal from another instance.

HOWEVER , printing the namespace __dict__ of the class, even after the creation of instances and the call of the "method" addu(), this namespace doesn't exposes a new object that could be identified to the method object different from the addu function.

What does it mean ?
It gives me the impression that as soon as a method object is created, it isn't destroyed, it lives in the memory (RAM).
But it lives hidden and only the processes that form the interpeter's functionning know how and where to find it.
This hidden object, the real method object, must have the ability to change the reference to the instance to which the function must be applied, or to reference None if it is called as an unbound method. That's what it seems to me, but it's only brain-storming hypothesis.

Does anybody know something on this interrogation ?


To answer to the question, it can be considered correct to call .upper and .lower functions , since in reality they are based on functionsas every method of a class.

However, the following result is special, probably because they are builtin methods/functions, not user's methods/functions as in my code.

x = 'hello'
print x.upper.__func__

result

    print x.upper.__func__
AttributeError: 'builtin_function_or_method' object has no attribute '__func__'
smci
  • 26,085
  • 16
  • 96
  • 138
eyquem
  • 24,028
  • 6
  • 35
  • 41
  • 1
    I've just realized that ``A.addu`` gives ```` and ``type(A.addu`` gives ```` ---WHILE--- ``A.__dict__['addu']`` gives ```` and ``type(A.__dict__['addu'])`` gives ```` . There's really a difference according the manner the object is reached. Using the ``.`` , dot notation, triggers the actionning of an hidden mechanism, that's what is reflected from my answer and from these two results. The methods are really mysterious things that operates in the secret dark of inner mechanism of Python. My opinion – eyquem Jan 08 '14 at 00:36
  • 2
    First thanks for the great answer. About your doubts: everytime `a1.addu` is accessed a new (temporary) object is created and then directly destroyed. Per coincidence those objects have the same id (because they are created at the same memory address). However if you keep the reference to the created object you will see different ids: `id(a1.addu) == id(a1.addu)` is True, because the temporaries are created and destroyed one after another and the same memory is reused, but `a1.addu is a1.addu` is False, because temporaries are simultaneously alive and have different addresses. – ead Aug 10 '18 at 08:32
3

In the following class definition:

class MyClass:
    """A simple example class"""
    def f(self):
        return 'hello world'
  • Class : MyClass
  • Function: f()
  • Method: None (Actually, not applicable)

Lets create an instance of the above class. We'll do this by assigning class object, i.e. MyClass() to var x

  x = MyClass()

Here,

  • Function: None
  • Method: x.f()

And lets not forget that the function object MyClass.f was used to define (internally) the method object x.f when we assigned x to MyClass()

Ketan
  • 1,489
  • 1
  • 14
  • 21
2

Basically, yes, Python does distinguish them, but in Python it is common to view methods as a subset of functions. Methods are associated with a class or instance, and "standalone functions" are not. Something that is a method is also a function, but there can be functions that are not methods.

As Jon Clements mentioned in his comment, though, the distinction is not so ironclad as in C++. Standalone functions can be "converted" into methods at runtime, and methods can be assigned to variables in such a way that they effectively behave no differently than standalone functions. So the boundary between methods and functions is permeable.

BrenBarn
  • 210,788
  • 30
  • 364
  • 352
  • But does the dot operator in the functions/methods mentioned still associate them with a string object? And are for example len() a stand alone function that takes a string object as an argument? – Q-bertsuit Jan 07 '14 at 21:18
  • 1
    Yes, the ones with a dot are methods, and yes `len`, is a function. – BrenBarn Jan 07 '14 at 21:19
  • @Q-bertsuit _"Methods are associated with a class or instance, and "standalone functions" are not. "_ However, what appears in the namespace ``__dict__`` of a class are functions, not methods. ,,,, _"Something that is a method is also a function"_ A method is more than a function sinc it is a packing of a function and an instance. See what I describe in my answer, please. What do you think of it ? – eyquem Jan 08 '14 at 00:24
  • @eyquem Although I appreciate the time and effort you put into your answer, it's a bit over my head. I'm just starting out learning Python, and for now I'm happy knowing that methods and functions have more complicated definitions than what I'm used to. Thank you for your time! +1 – Q-bertsuit Jan 08 '14 at 08:13
1

Took snippet from this answer

Following are the changes

  • Unbound methods (methods bound to a class object) are no longer available.
  • unbound method -> function
  • type instancemethod are removed from Python 3

More about methods on this answer

About methods on Python docs

More about classes on Python docs

import sys
print(sys.version)
# 3.9.0rc2 (tags/v3.9.0rc2:2bd31b5, Sep 17 2020, 00:58:12) [MSC v.1927 64 bit (AMD64)]

class A:
  def a(self): pass

print(A.a)
# <unbound method A.a>
# <function A.a at 0x00000200FBE121F0>

print(type(A.a))
# <type 'instancemethod'>
# <class 'function'>

print(A().a)
# <bound method A.a of <__main__.A instance at 0x107070d88>>
# <bound method A.a of <__main__.A object at 0x00000200FBB12640>>

print(type(A().a))
# <type 'instancemethod'>
# <class 'method'>
Smart Manoj
  • 3,837
  • 2
  • 24
  • 45