2

In Python Language Reference, Chapter 3 Datamodel, why is "instance method" listed under "callable types", while "static method object" and "class method object" are listed under "internal types"?

Callable types These are the types to which the function call operation (see section Calls) can be applied ...

Instance methods ...

Internal types A few types used internally by the interpreter are exposed to the user. Their definitions may change with future versions of the interpreter, but they are mentioned here for completeness. ...

Static method objects ...

Class method objects ...

Shouldn't static and class method objects also be callable types?

Community
  • 1
  • 1
Tim
  • 1
  • 141
  • 372
  • 590

2 Answers2

5

No, staticmethod's and classmethods are not callable, no rationale to do so was found.

>>> def foo():
...     print("hello") 
>>> s = staticmethod(foo)
>>> s()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable

They are meant to be invoked via the descriptor protocol and (usually) return a callable:

>>> s.__get__(foo)()
hello

this isn't the most common form, though. Usually a descriptor is invoked automatically upon attribute access, as the descriptor how-to states:

A descriptor can be called directly by its method name. For example, d.__get__(obj).

Alternatively, it is more common for a descriptor to be invoked automatically upon attribute access. For example, obj.d looks up d in the dictionary of obj. If d defines the method __get__(), then d.__get__(obj) is invoked according to the precedence rules listed below.

Community
  • 1
  • 1
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
  • Thanks. Are ordinary methods of a class (i.e. methods of a class which are neither static or class methods) callable? – Tim Sep 15 '17 at 16:10
  • In what cases are static and class methods not used as attributes of a class? – Tim Sep 15 '17 at 16:12
  • Yes @Tim, they are. Functions are descriptors who's `__get__` method returns the method, when used in classes and an attribute look-up is performed the `function.__get__` is invoked and returns the method. So, both function and methods are callable. I haven't seen any cases where `static/class` methods are used outside classes, I just used that example because it is shorter :-) – Dimitris Fasarakis Hilliard Sep 15 '17 at 16:16
  • "Functions are descriptors" do you mean a function defined with `def` outside any class is a descriptor? e.g. `foo` in your example. – Tim Sep 15 '17 at 16:18
  • @Tim yup, see `foo.__get__(foo)` it returns a method object. Raymond Hettinger has written [a nice tutorial on these](https://docs.python.org/3.6/howto/descriptor.html#functions-and-methods), it is a nice source of information on all things-descriptor. – Dimitris Fasarakis Hilliard Sep 15 '17 at 16:24
  • 1
    @Tim A descriptor is *any* object that defines `__get__` (and possibly `__set__`). The only time `__get__` is invoked automatically is when the descriptor is the result of an attribute lookup (`MyClass.foo` or `MyClass().foo`). – chepner Sep 15 '17 at 16:26
  • I am confused: static and class methods are not callable because they are descriptors, while ordinary methods of a class (i.e. methods of a class which are neither static or class methods) and functions which are not attributes of classes are both descriptors and callable. – Tim Sep 15 '17 at 16:26
  • @Tim I understand the confusion. The fact that they are descriptors isn't the reason why they are not callable. The fact that no use for them beeing callable is the reason for them not being callable. Functions, via descriptors, offered a convenient way to create methods but we still need functions to be callable (and that's why they are). – Dimitris Fasarakis Hilliard Sep 15 '17 at 16:30
  • (1) "The fact that no use for them beeing callable is the reason for them not being callable." Can you say more about the actual reason for something to be a callable or not? (2) Since `foo` in your example is a descriptor, why doesn't `foo.__get__(foo)()` work just like `s.__get__(foo)()`? – Tim Sep 15 '17 at 16:34
  • @Tim As for (1) I urge you to take a look at [this message](https://bugs.python.org/msg240843) by a core cpython dev on why not all descriptors should be callable. As for (2) `foo.__get__(foo)()` returns a bound *method*, so `self` (the function object here) is implicitly passed (that's why you get an error of "takes 0 positionals but 1 was given". `staticmethods` *don't pass any implicit arguments* to the callable they wrap ;-) – Dimitris Fasarakis Hilliard Sep 15 '17 at 16:41
4

The staticmethod objects are not callable:

Python 3.5.3 (default, Jan 19 2017, 14:11:04) 
[GCC 6.3.0 20170118] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> staticmethod(lambda x: print(x))
<staticmethod object at 0x7f8499f1ebe0>
>>> meth = staticmethod(lambda: print('static method called'))
>>> meth()
Traceback (most recent call last):

However they implement the descriptor protocol method __get__. The __get__ method then returns an actual callable object.

File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable
>>> meth.__get__(object, object())()
static method called

When you store the staticmethod object into a class attribute, and then look it up, the __get__ method is called implicitly.

  • 1
    Relevant quote from the docs: _"Static method objects are not themselves callable, although the objects they wrap usually are."_ – Aran-Fey Sep 15 '17 at 15:50