From kirby.urner at gmail.com Wed Apr 10 15:34:09 2019 From: kirby.urner at gmail.com (kirby urner) Date: Wed, 10 Apr 2019 12:34:09 -0700 Subject: [Edu-sig] What is an "object"?: Polyhedrons & OOP Message-ID: Of course the literature contains numerous definitions. A similar question might be "what is a noun?". Objects are "that which the nouns name" in the Pythonic paradigm. They (the objects) live in memory at id() addresses ("like street addresses" I might tell my students). However, impressionable minds need more to hang a hat on that just boring grammar words (like "noun"). In UML (universal markup language) we have our customary symbols and diagrams: https://atomicobject.com/resources/oo-programming/abstraction-and-identity I often use a Creature -> Animal -> Mammal -> subclasses of Mammal taxonomy, when introducing inheritance and what we call the MRO (method resolution order). Another association of "object" we might build upon is "polyhedron" or "that which has shape". class Polyhedron: def __init__(self, v, f): self.v = v self.f = f self.e = v + f - 2 # euler's law for polyhedra def scale(self, factor): """ scale volume by factor, beget a new poly """ return type(self)(vol = self.volume * factor) __mul__ = __rmul__ = scale class Tetrahedron(Polyhedron): def __init__(self, vol=1): super().__init__(v=4, f=4) self.volume = vol class A(Tetrahedron): def __init__(self): super().__init__(vol=1/24) class B(Tetrahedron): def __init__(self): super().__init__(vol=1/24) # etc. (S, E, T) class Cube(Polyhedron): def __init__(self, vol=3): super().__init__(v=8, f=6) self.volume = vol class Octahedron(Polyhedron): def __init__(self, vol=4): super().__init__(v=6, f=8) self.volume = vol etc. (longer list of subclasses). If the Learning to Code curricula were to feature more source of this nature, we could facilitate reaching out to the geometry teachers with an intuitive picture of "dot notation" as a means of accessing "containers" of a very literal kind, if abstract. Associations around "object" have something concrete to build on, adding generic methods such as rotate() -- about what axis? -- and translate() -- for moving the shape relative to others, or to an origin (could involve creating a new shape at the new place, relative to the old). We could easily add surface area as another attribute, along with default edge length corresponding to our default volumes (YMMV in terms of what defaults your curriculum chooses). Indeed this is the right place to emphasize the power law, that changing all edges by a factor of n, e.g. doubling them (n=2) changes area by n**2 and volume by n**3. A selling point of the simple code base shown above is I'm not trying to do anything vectorial yet i.e. the shapes are so far coordinate free. We're free to turn to actual physical models and other media besides source code, to flesh out the concepts we're talking about. OO wins. Geometry wins. Dot notation wins. Python wins. I've been taking this tack in my Youtubes lately, building up a stash for a science fiction time when these ideas are more mainstream. Not that this focus on Polyhedrons as paradigm objects is all that esoteric. Square and Circle types have been common in textbooks at least. There's a bias against "3D" and I suppose that's what I'm countering, as speaking experientially, we do not live in Flatland. The approach to coding I'm advocating is also encouragement for spatial, not just planar, visualizations. Euclidean proofs may be more involved, however we have other generalizations such as Euler's Law for Polyhedra and Decartes' Deficit to introduce. Having the OO experience tie in with spatial geometry more intimately provides greater opportunities for imaginative play, and exercises the computing machinery in ways it's already very good at. Kirby -------------- next part -------------- An HTML attachment was scrubbed... URL: From kirby.urner at gmail.com Tue Apr 16 14:49:48 2019 From: kirby.urner at gmail.com (kirby urner) Date: Tue, 16 Apr 2019 11:49:48 -0700 Subject: [Edu-sig] what is 'self'? (plus link to Trey's article on callability) Message-ID: 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: From wes.turner at gmail.com Tue Apr 16 15:37:31 2019 From: wes.turner at gmail.com (Wes Turner) Date: Tue, 16 Apr 2019 15:37:31 -0400 Subject: [Edu-sig] what is 'self'? (plus link to Trey's article on callability) In-Reply-To: References: Message-ID: 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 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: From wes.turner at gmail.com Tue Apr 16 15:43:08 2019 From: wes.turner at gmail.com (Wes Turner) Date: Tue, 16 Apr 2019 15:43:08 -0400 Subject: [Edu-sig] what is 'self'? (plus link to Trey's article on callability) In-Reply-To: References: Message-ID: > 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 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 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: From wes.turner at gmail.com Tue Apr 16 15:44:44 2019 From: wes.turner at gmail.com (Wes Turner) Date: Tue, 16 Apr 2019 15:44:44 -0400 Subject: [Edu-sig] what is 'self'? (plus link to Trey's article on callability) In-Reply-To: References: Message-ID: Or ``a.__get__('x')`` ? On Tuesday, April 16, 2019, Wes Turner 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 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 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 >>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From kirby.urner at gmail.com Tue Apr 16 16:51:04 2019 From: kirby.urner at gmail.com (kirby urner) Date: Tue, 16 Apr 2019 13:51:04 -0700 Subject: [Edu-sig] Descriptor concept clarifies Python behind the scenes In-Reply-To: References: Message-ID: Perfect to bring in the Descriptor protocol, right when we're talking about 'self' and also (per Trey's article), the different species of callable, i.e. functions, methods (functions inside classes) and the classes themselves (also callables, passing through to __init__, no need for keyword 'new' as in Java or Javascript). The code for a Property class in: https://docs.python.org/3/howto/descriptor.html#properties is about my deepest dive in an introductory course (and a longish one at that). We looked at it last week. Tonight I look a little more at Descriptors so all this edu-sig work counts as warming up. This isn't "cheat sheet" level Python, that's for sure. The actual property class (a built-in) isn't actually implemented in pure Python. The code in the docs is like "if it were" (written in Python) and to prove they're not kidding, when I introduce one of those Circle types (ala Raymond Hettinger) with co-varying attributes (change the radius, area and circumference change; change the circumference, radius and area change... etc.) wherein at the top I go: from modelproperty import Property as property # <-- overwrite builtin property with doc simulation class Circle: def __init__(radius = 1): self.radius = 1 # trigger setter (this won't store directly to self.__dict__['radius'] thanks to @property) @property def radius(self): # one could do the recomputations upon getting but... return self._radius @radius.setter def radius(self, r): # it makes the most sense to update other dimensions when setting, no? self._radius = r self._area = pi * r * r self._circumference = 2 * pi * r and so on. Everything works the same. Even though we're using doc code instead. With Property in view, one can see how circle.radius = 3 is triggering circle.radius.__set__(3), because radius is now the name of a Property instance (thanks to decorator syntax), and the radius.__set__ method invokes a stored method fset The first @property is swallowing the immediately following radius method whole, and storing it in fget (a property attribute). The invocation of @radius.setter then calls a Property method: def setter(self, fset): return type(self)(self.fget, fset, self.fdel, self.__doc__) which cleverly returns a whole new Property instance, by keeping self.fget as it was, while taking in fset as the new kid on the block. The newer Property is now armed with what it needs, to make radius play well with the others (area and circumference). Kirby On Tue, Apr 16, 2019 at 12:37 PM Wes Turner 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__). > """ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From merav at datasociety.com Thu Apr 18 14:52:35 2019 From: merav at datasociety.com (Merav Yuravlivker) Date: Thu, 18 Apr 2019 14:52:35 -0400 Subject: [Edu-sig] Part-time opportunities for Python instructors Message-ID: Hi there, My name is Merav Yuravlivker, and I'm the CEO of Data Society - we deliver data science academies to Fortune 500 companies, government agencies, and other international organizations. We're currently looking for part-time Python instructors and TAs, and my friend Jackie Kazil recommended I reach out to you and your list serv. All of these opportunities can be available for people who are employed full-time, professors, or grad students. We pay well and provide all the materials for the instructor, as well as instructor training and support. If possible, would you please be able to share the following blurb? Please let me know if there is anything else you need from me. Much appreciated! Best, Merav --- Data Society, a fast-growing data science training company, is looking for awesome Python instructors and TAs! We deliver data academies to Fortune 500 companies, government agencies, and international organizations. All of our content is built in-house by an expert team of data scientists and instructional designers, so you can focus on what you do best - teach professionals how to find new insights and make their jobs easier. We currently have a few openings for TAs, as well as part-time instructors - all of these opportunities can be available for people who are employed full-time, professors, or grad students. We pay competitively, have a great support team, and provide amazing opportunities for additional projects if you're interested. To learn more, please visit our page for current opportunities , or simply reach out to Merav at merav at datasociety.com. -- Schedule a time to meet Merav Yuravlivker Data Society, Chief Executive Officer and Co-founder 777 6th Street NW, 11th Floor Washington, D.C., 20001 Enterprise: solutions.datasociety.com Consumer: datasociety.com -------------- next part -------------- An HTML attachment was scrubbed... URL: