2

I've seen a couple of times methods being called on the type of an object instead of the object itself. What might the reasons for that be, especially with special methods?

Example from documentation: "For instance, if a class defines a method named _getitem_(), and x is an instance of this class, then x[i] is roughly equivalent to type(x)._getitem_(x, i)." https://docs.python.org/3/reference/datamodel.html#special-method-names

I realize the question might be too general, but if you would give a list of possible situations where such a pattern could be used and maybe provide some links to relevant documentation, I would greatly appreciate it.

Le Nod
  • 31
  • 4
  • `type(obj)` returns the class of `obj`. If you explicitly want to call a method on the class, well, that’s what you’d do. It seems rather unnecessary though, since if the method is a `@classmethod` it can be called on an instance just as well with the same effect. – deceze Nov 16 '22 at 04:38
  • I do understand that, yet I still see examples of using type(obj).method() (in reliable sources like PEPs). That makes me think there might be situations where this would be necessary or preferable, but I wasn't able to find any relevant information. – Le Nod Nov 16 '22 at 04:43
  • 1
    Related: https://stackoverflow.com/q/34490998/3004881 – Dan Getz Nov 16 '22 at 12:11

1 Answers1

3

The main reason to do this is to simulate how special methods are looked up implicitly. When you do len(seq), the underlying code is (mostly) equivalent to type(seq).__len__(seq), bypassing the instance itself (preventing someone from assigning to seq.__len__ and changing how len behaves for that instance). If you're writing code intended to match said behavior (bypassing instance attributes in favor of class attributes), this is a close approximation.

Note that the docs you read with this example aren't suggesting you use the roughly equivalent method. They're explaining how the syntax maps onto the underlying method calls, and making it clear it's bypassing instance attribute lookup, that's all. You're not supposed to actually write that code in all but the weirdest of cases (the Python level implementation of some C-accelerated modules, where the Python implementation is used by PyPy and rarely by CPython, might use this code to get exact behavioral compatibility regardless of whether the Python code or the C-accelerated code is in use), but it's useful to know for when you do need that exact compatibility, or just when it's slightly better for correctness, e.g. the Python implementation of functools.total_ordering uses this approach to look up the rich comparison methods the same way the operator forms of < and company do under the hood.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Thank you! Since special method lookup seems to be key here, I think it's appropriate to attach the link to the docs here: https://docs.python.org/3/reference/datamodel.html#special-method-lookup – Le Nod Nov 16 '22 at 13:16
  • @LeNod: Done. I'd left it off because you link the same page, but a direct section link won't hurt. – ShadowRanger Nov 16 '22 at 17:04
  • Beautiful! Didn't realize that they are literally on the same page until you pointed it out btw, for me they were on different tabs :) – Le Nod Nov 16 '22 at 18:33