[Edu-sig] what is 'self'? (plus link to Trey's article on callability)

Wes Turner wes.turner at gmail.com
Tue Apr 16 15:43:08 EDT 2019


> Direct Call
The simplest and least common call is when user code directly invokes a
descriptor method: x.__get__(a).

Should this be `a.__get__(x)`?

On Tuesday, April 16, 2019, Wes Turner <wes.turner at gmail.com> wrote:

> When you access an attribute of a class object (a dict), the class
> attribute is looked up by __get__().
> the class's instance of that function attribute is 'bound'; it receives
> 'self' (an object reference) as its first argument.
>
> If you write your own __get__ (e.g. with functools.partial or
> functools.wrap),
> or try and assign a function to a class [instance],
> or create a @staticmethod or a @classmethod,
> you can more fully understand how methods receive self as their first
> argument.
>
> - https://docs.python.org/3/howto/descriptor.html#functions-and-methods
> - https://python-reference.readthedocs.io/en/latest/docs/dunderdsc/ :
>
> """
> Descriptor Protocol
> In general, a descriptor is an object attribute with “binding behavior”,
> one whose attribute access has been overridden by methods in the descriptor
> protocol: __get__(), __set__(), and __delete__(). If any of those methods
> are defined for an object, it is said to be a descriptor.
>
> The default behavior for attribute access is to get, set, or delete the
> attribute from an object’s dictionary. For instance, a.x has a lookup chain
> starting with a.__dict__[‘x’], then type(a).__dict__[‘x’], and continuing
> through the base classes of type(a) excluding metaclasses.
>
> However, if the looked-up value is an object defining one of the
> descriptor methods, then Python may override the default behavior and
> invoke the descriptor method instead. Where this occurs in the precedence
> chain depends on which descriptor methods were defined and how they were
> called. Note that descriptors are only invoked for new style objects or
> classes (ones that subclass object() or type()).
>
> The starting point for descriptor invocation is a binding, a.x. How the
> arguments are assembled depends on a:
>
> Direct Call
> The simplest and least common call is when user code directly invokes a
> descriptor method: x.__get__(a).
>
> Instance Binding
> If binding to a new-style object instance, a.x is transformed into the
> call: type(a).__dict__[‘x’].__get__(a, type(a)).
>
> Class Binding
> If binding to a new-style class, A.x is transformed into the call:
> A.__dict__[‘x’].__get__(None, A).
>
> Super Binding
> If a is an instance of super, then the binding super(B, obj).m() searches
> obj.__class__.__mro__ for the base class A immediately preceding B and then
> invokes the descriptor with the call: A.__dict__[‘m’].__get__(obj,
> obj.__class__).
> """
>
>
> On Tuesday, April 16, 2019, kirby urner <kirby.urner at gmail.com> wrote:
>
>>
>> If we're ever at a loss for what to talk about, in this context, of
>> Python teachers, I could recommend a list of default topics, one of which
>> would always be...
>>
>> What is this 'self'?
>>
>> The self appears right when we introduce the class construct (keyword
>> class).  And then we say things like "Python provides it" or "Python fills
>> it in".  What is "it" then?  "It" is "the instance".  For some, things are
>> starting to get muddy.
>>
>> For coders familiar with OOP style grammars i.e. they're coming from
>> another language such as JavaScript or Java (quite different I realize),
>> they've got a sense of it, from keyword 'this'.
>>
>> However Python is widely touted as a gateway language into OOP style
>> thinking, so we get a lot of first timers.  We owe them a clear picture of
>> self.
>>
>> One andragogical technique comes straight from the docs:
>>
>> instance = C()
>> C.method(instance)   # <-- needs instance as argument
>>
>> is equivalent to:
>>
>> instance = C()
>> instance.method()  # <-- instance is "subject" as in subject.verb()
>>
>> ... of course we may add additional arguments at will, but lets keep it
>> simple.
>>
>> In OOP, all the selves share the same template or class code, so how is
>> Python to distinguish one self from another?
>>
>> It's not like each self is carrying around a copy of the method code. The
>> model is more like having DNA in common (a shared genetic core).
>>
>> As in:
>>
>> class Creature:
>>
>>     def eat(self, food):  # <--- needs to know which self
>>         self.stomach.append(food)
>>
>> With:
>>
>> instance.eat("spaghetti")  # <-- self known to Python
>>
>> we have enough info to figure out which self, and Python obligingly
>> brings it forward, to fill the placeholder, usually 'self'.
>>
>> With:
>>
>> Creature.eat(instance, "spaghetti")  # self supplied by the caller
>>
>> we're not giving enough distinguishing information with generic Creature,
>> and so instance has to be provided, as the self.
>>
>> Further andragogical elaboration involves showing what I mean by "usually
>> 'self'" i.e. self is not a keyword but a placeholder.
>>
>> Here I tend to go for a Chinese character substitute, e.g. for "Ego", to
>> remind the learner of Unicode in addition.  Emoji can't be Python names or
>> I might go for one of them.
>>
>>         *            *            *
>>
>> Another good article by Trey Hunner just came out.  He's one of the more
>> prolific Python teachers *that I know about* (an important caveat as I'm
>> always missing *a lot*):
>>
>> https://treyhunner.com/2019/04/is-it-a-class-or-a-function-
>> its-a-callable/
>>
>> He takes up the issue of "callables that are functions" versus "callables
>> that are actually types (classes)".
>>
>> That can help with fine tuning one's sense of what a "type" is, plus
>> callability in general is a bridge to decorators, and this article
>> definitely goes there.
>>
>> Kirby
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/edu-sig/attachments/20190416/ee757c4c/attachment.html>


More information about the Edu-sig mailing list