Or ``a.__get__('x')`` ? On Tuesday, April 16, 2019, Wes Turner <wes.tur...@gmail.com> wrote:
> > 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-i >>> ts-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