9

I know that in Python we have to supply __get__ function when implementing a descriptor. The interface is like:

def __get__(self, obj, objtype=None):
    pass

My question is:

Why we have to supply objtype arg? What is objtype used for?

I did not see some examples about the usage of this arg.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
ruanhao
  • 4,663
  • 6
  • 28
  • 43
  • [The documentation of `object.__get__`](https://docs.python.org/3.4/reference/datamodel.html?highlight=__get__#object.__get__) does not mention `objtype`. Where did you read about it? –  May 25 '15 at 08:39
  • 2
    @LutzHorn `owner` is `objtype` in this case, i.e the class. – Ashwini Chaudhary May 25 '15 at 08:40
  • http://intermediatepythonista.com/classes-and-objects-ii-descriptors – Padraic Cunningham May 25 '15 at 09:14
  • Part of your confusion is that you have the function prototype wrong. According to the docs linked by Lutz Horn, `owner` (not `objtype`, as already pointed out) does _not_ default to `None` in any version of Python. – Kevin J. Chase May 25 '15 at 22:49

2 Answers2

3

It gives users an option to do something with the class that was used to call the descriptor.

In normal cases when the descriptor is called through the instance we can get the object type by calling type(ins).

But when it is called through the class ins will be Noneand we won't be able to access the class object if the third argument was not present.


Take functions in Python for example, each function is an instance of types.FunctionType and has a __get__ method that can be used to make that function a bound or unbound method.

>>> from types import FunctionType
>>> class A(object):
    pass
...
>>> def func(self):
    print self
...
>>> ins = A()
>>> types.FunctionType.__get__(func, ins, A)() # instance passed
<__main__.A object at 0x10f07a150>
>>> types.FunctionType.__get__(func, None, A)  # instance not passed
<unbound method A.func>
>>> types.FunctionType.__get__(func, None, A)()
Traceback (most recent call last):
  File "<ipython-input-211-d02d994cdf6b>", line 1, in <module>
    types.FunctionType.__get__(func, None, A)()
TypeError: unbound method func() must be called with A instance as first argument (got nothing instead)
>>> types.FunctionType.__get__(func, None, A)(A())
<__main__.A object at 0x10df1f6d0>
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • If it is useful for `__get__`, why is the `owner` parameter absent from `__set__` and `__delete__` as well? – Géry Ogam Mar 22 '21 at 18:44
  • @Maggyero Any usecases you could think of having `owner` or `objtype` in `__set__` and `__delete__`, when they are called from class not instance? – Ashwini Chaudhary Mar 23 '21 at 01:52
  • An application I can think of is managing access to *class* attributes (similar to [managing access to *instance* attributes](https://docs.python.org/3/howto/descriptor.html#managed-attributes)), where `A.x` would look up `A._x` (already possible thanks to the `owner` parameter), `A.x = 'foo'` would update `A._x` (not currently possible) and `del A.x` would delete `A._x` (not currently possible). – Géry Ogam Mar 23 '21 at 11:06
0

From the documentation of object.__get__(self, instance, owner):

owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner.

So you don't supply owner, it is set depending on how __get__ is called.

  • 1
    Do you know some circumstance where *owner* is used? I just don't know the purpose of this arg. – ruanhao May 25 '15 at 09:06