> 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.tur...@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.ur...@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 >> >>
_______________________________________________ Edu-sig mailing list Edu-sig@python.org https://mail.python.org/mailman/listinfo/edu-sig