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

Wes Turner wes.turner at gmail.com
Tue Apr 16 15:37:31 EDT 2019


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/2dabedf0/attachment-0001.html>


More information about the Edu-sig mailing list