dunder-docs (was Python is DOOMED! Again!)

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Feb 2 07:06:13 EST 2015


Devin Jeanpierre wrote:

> -- Devin
> 
> On Sun, Feb 1, 2015 at 11:15 PM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> Gregory Ewing wrote:
>>
>>> Steven D'Aprano wrote:
>>>>     [quote]
>>>>     If the object has a method named __dir__(), this method will
>>>>     be called and must return the list of attributes.
>>>>     [end quote]
>>>>
>>>> The first inaccuracy is that like all (nearly all?) dunder methods,
>>>> Python only looks for __dir__ on the class, not the instance itself.
>>>
>>> It says "method", not "attribute", so technically
>>> it's correct. The methods of an object are defined
>>> by what's in its class.
>>
>> Citation please. I'd like to see where that is defined.
> 
> https://docs.python.org/3/glossary.html#term-method

Run this code using any version of Python from 1.5 onwards, and you will see
that the definition is wrong:


# === cut ===

class K:
    def f(self): pass

# Define a function OUTSIDE of a class body.
def g(self): pass

K.g = g
instance = K()
assert type(instance.f) is type(instance.g)
print(type(instance.f))
print(type(instance.g))

# === cut ===


Both K.f and K.g are methods, even though only one meets the definition
given in the glossary. The glossary is wrong.

Or rather, it is not so much that it is *wrong*, but that it is incomplete
and over-simplified. It describes how methods are normally (but not always)
defined, but not what they are. It is rather like defining "coffee" as the
milky drink you buy from Starbucks, then insisting that the black liquid
that you drank in an Italian restaurant cannot be coffee because you didn't
buy it from Starbucks.

Glossary entries are typically simplified, not exhaustive. It is not wise to
take a three line glossary entry as a complete, definite explanation. In
this case the glossary fails to tell you that methods are not *required* to
be defined inside a class body, that is merely the usual way to do it.



>> Even if it is so defined, the definition is wrong. You can define methods
>> on an instance. I showed an example of an instance with its own personal
>> __dir__ method, and showed that dir() ignores it if the instance belongs
>> to a new-style class but uses it if it is an old-style class.
> 
> You didn't define a method, you defined a callable attribute.

That is wrong. I defined a method:

py> from types import MethodType
py> type(instance.f) is MethodType
True


instance.f is a method by the glossary definition. Its type is identical to
types.MethodType, which is what I used to create a method by hand.

I could also call the descriptor __get__ method by hand, if you prefer:

py> def h(self): pass
...
py> method = h.__get__(K, instance)
py> assert type(method) is type(instance.f)
py> print(method)
<bound method type.h of <class '__main__.K'>>



-- 
Steven




More information about the Python-list mailing list