[Edu-sig] python versus __python__
Going into my new presentation manager materials (perhaps using the same Pygame engine I used at OSCON, but as a general purpose module, i.e. not tied up in that specific content) is the distinction between two kinds of Python: Python and __Python__. You really get to a new level with Python when you start using its underunder. And that occurs, for many, right when they define a first class (or user type): in the form of __init__. __new__ comes even later (a paradox). Another fissure defining beginner and advanced: operator overloading. That's how it was in C++ books: we'll get to that later. Considered an advanced feature, not even featured in the original Java from Sun. So a logical course progression might involve doing a lot of non-underunder stuff at first, exploring but without much introspecting. Because as soon as you introspect, ala dir(1), you're into underunder land, and that takes advanced thinking to negotiate.[1] Now, just saying there're these two levels isn't to say we can't be up front about their being there. I'll tell a class we're tackling Python in two goes, saving __python__ for Part 2. I look at Wittgenstein's PI the same way. Part 2 is more subtle, and you get more power. You get to redefine what you mean by + and *. Wow. Snake charmers enter here. Now there's another way Python gets advanced, which is less about getting more deeply into Python, and more about getting more deeply into something else, *using* Python. That's like when we import a module giving us a wrap of some external game engine, wherein to construct simulations and so on ala that project to teach Arabic to soldiers at West Point -- a demo at Pycon 2005 in DC. So you have different ways of advancing in Python: into the language more deeply, to mastery of underunder, metaclasses and beyond; and into foreign territory, but with Python as your guidebook and phrase book, giving you confidence amidst all these alien-seeming APIs. I suppose poking around under the hood, looking at the C or whatever's puppeting the Python interpreter, is yet a third direction in which to advance. You'll see how underunder is implemented under the hood. But it won't be in Python per se, but in Python byte code on a VM (Python-the-agile skins many a system language -- including in cell phones). Kirby [1] IDLE 1.1 >>> dir(1) ['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__str__', '__sub__', '__truediv__', '__xor__'] ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
[Edu-sig] python versus __python__
Kirby - >PS: since you've been studying subclassing primitive types using __new__, >maybe you could show us a user-defined floating point type that reports two >numbers equal if their absolute value difference is less than e. Anyone? My studies on the subject of subclassing the complex type have been quickly abandoned - it becoming clear that the fact the .real and .imag are read-only defeats the ideas I had for it. I guess I might have tried harder to see if one could override that behavior in a subclass, but my decision to move on is based on the fact that if what I like to think I am pursuing is simplicity, changing the fundamental behavior of a built-in, even if doable, would not seem to be a path to it. But as these dead-end explorations usually do, got me thinking about things not previously confronted. Like the simple question of what is "float" fundamentally, a function - as in float(1) - or a numeric type. And by subclassing "float", is one subclassing a function or a type. Is just some shadowing of a name going on in the netherworld, or are the function and type more intimately related in that realm? Us non C programmers look forward to PyPy for the view of the netherworld it will give us. In truth I expect PyPy to bring a new burst of creative energy to the Python world, just by opening up the possibility of lower level exploration to a wider group of folks. As the answer to most of the "why Python" questions that we all try to answer on some technical level, in the end - IMO - boil done to largely that, the creative energy surrounding it. Perhaps that understanding should provoke me into whining less about the moving target that Python seems sometimes to be. Perhaps Guido understands either consciously or intuitively that less openness to change - with all the downsides of such change - would subvert that essential energy aura in which Python persists. Art ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Kirby Urner wrote: >Going into my new presentation manager materials (perhaps using the same >Pygame engine I used at OSCON, but as a general purpose module, i.e. not >tied up in that specific content) is the distinction between two kinds of >Python: Python and __Python__. > > The ego and the id of it... is how I sometimes think of it. >You really get to a new level with Python when you start using its >underunder. And that occurs, for many, right when they define a first class >(or user type): in the form of __init__. __new__ comes even later (a >paradox). > > Just posted to python-list on this, having found that subclassing numeric types is done at the __new__ level, not the __init__ level. I see __init__ as everyday waking consciousness, and __new__ inhabiting the netherworld. But making the subconscious conscious leads to good mental health. Of which I am th strongest of advocates. And I am trying to dredge up __new__ to the conscious level. >Another fissure defining beginner and advanced: operator overloading. >That's how it was in C++ books: we'll get to that later. Considered an >advanced feature, not even featured in the original Java from Sun. > > This is something I felt comfortable exploring very early on - to the extent of having overused it. I would hate to see you back-end that, as I think it is kind of fun to play with. "let's change the boring old rules of math..." kind of thing. I understand where you are going ,I think, but I would advocate being a bit less literal in finding the demarcation at __xxx__. You see properties as above ground, and everyday - I still see them as convenience for some once-in-a-while-necessary magic calls to __xxx__ fairies. I think the dividing line has something more to do with the degree of introspection that one undertakes. Deeper levels of introspection provokes one into a confrontation with one's Pythonic mortality ;) Art ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
> This is something I felt comfortable exploring very early on - to the > extent of having overused it. I would hate to see you back-end that, as > I think it is kind of fun to play with. "let's change the boring old > rules of math..." kind of thing. > Yes, operator overloading is a big part of my "math through programming" curriculum. You want your * and + operators to be "modulo N" for example, the better to appreciate group theory. Or we might use * to mean 'compose' as in: >>> def f(x): return 2*x + 1 >>> def g(x): return x**2 >>> class F(object): def __init__(self, func): self.func = func def __mul__(self, other): return F(lambda x: self.func(other.func(x))) def __call__(self,x): return self.func(x) >>> of = F(f) >>> og = F(g) >>> of(2) 5 >>> f(g(2)) 9 >>> h = of*og >>> h(2) 9 >>> j = og*of >>> j(2) 25 I think where a lot of kids will first encounter underunder is not in __init__ but in __name__, as in that "__name__ == '__main__'" trick for getting scripts to run at the command line, even as they also serve as class & function repositories for snake charmers in a Python shell. Kirby PS: since you've been studying subclassing primitive types using __new__, maybe you could show us a user-defined floating point type that reports two numbers equal if their absolute value difference is less than e. Anyone? ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Arthur wrote: >Us non C programmers look forward to PyPy for the view of the netherworld it >will >give us. In truth I expect PyPy to bring a new burst of creative energy to the >Python world, just by opening up the possibility of lower level exploration to >a wider group of folks. > > So I go the next step, download PyPy, and get at app_complex.py - which is the pypy implementation of the Python complex function, implemented in Python - all as advertised. Which is nicely transparent to someone who can read Python well-enough - as advertised. Not too surprisingly, it uses our friend property to implement the read only aspect of .real and .imag, so that by simply commenting out the property functions I seem to have what I think I want, the ability to work with a complex number object, with the ability to write directly to .real and .imag. Probably from there I rename it from "complex" to "Complex" - I like case sensitivity for these kind of reasons - so that I remember I am working with the Python function not the built-in function, then inherit from it as I was intending to do with the builtin, and then plug it into PyGeo. Sacrificing performance - no doubt - with the upside of running it through some paces (the pypy module acknowledges it is not well tested, and if there are any issues perhaps they will be uncovered, and contributing to pypy in any small way seems worthwhile), seeing if the architecture I had in mind is actually sensible, and seeing if I discover why there was a decision to make .real,.imag read only as to the builtin. Yup - pypy is going to change things. Art ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Arthur wrote: > Arthur wrote: > >> Us non C programmers look forward to PyPy for the view of the >> netherworld it will >> give us. In truth I expect PyPy to bring a new burst of creative >> energy to the >> Python world, just by opening up the possibility of lower level >> exploration to a wider group of folks. >> >> > So I go the next step, download PyPy, and get at app_complex.py - > which is the pypy implementation of the Python complex function, > implemented in Python - all as advertised. > > Which is nicely transparent to someone who can read Python well-enough > - as advertised. And which, BTW, serves as a nice reference for techniques of operator overloading - which I have always found get a bit tricky once one gets beyond the simplest form of it. I had used what I find in Numeric's UserArray as my previous reference - nice to have something else to study a bit. Art ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Arthur wrote: > My studies on the subject of subclassing the complex type have been quickly > abandoned - it becoming clear that the fact the .real and .imag are read-only > defeats the ideas I had for it. Ahh: complex is (as are bool, int, long, string, and unicode) immutable. Changing such types to be mutable is "nasty" -- reuse of an immutable is done by referring to the same object, while reuse of an immutable needs a copy. If you do make one of these mutable, be sure to eliminate the hash function, or you won't be able to have it a key in a dictionary. Typically immutables are considered "identical" if they have identical state. Conceptually there should be no way to tell the difference between two distinct but equal immutables and the same immutable used twice. In fact, you can just check if id(one) == id(other), but that is "cheating" -- the "no way to tell" avoids precisely this trick. By the way, before you get too involved in playing with this stuff, there is a nasty surprise waiting to bite you. When you are comparing ids, be sure to compare ids of named things, not expressions. You might be surprised to learn: id(math.log(math.pi)) == id(math.log(math.e))! It is fun to try to figure out why. I'll post the answer tomorrow if nobody gets it by then. > But as these dead-end explorations usually do, got me thinking about things > not previously confronted. Like the simple question of what is "float" > fundamentally, a function - as in float(1) - or a numeric type. And by > subclassing "float", is one subclassing a function or a type. > Is just some shadowing of a name going on in the netherworld, or are > the function and type more intimately related in that realm? If you define a class named PyGeoTriangle, you create new instances with PyGeoTriangle(). Same with types (especially as we head into the brave new world of "new-style objects"). The changes in Python are heading towards a unification of types and classes, but that cannot fully happen until Python 3.0 (at least). Why not? -- old-style classes and new-style classes behave differently under the covers. So eventually (and in many cases now), a type name is just a predefined new-style class name. New-style classes and standard types can be made to behave quite the same, but old-style classes cannot. Unfortunately, some basic parts of Python (Exception comes to mind) use old-style classes. Code that people have written to run with Exception, living in some dark lab in northern New Jersey (for example), would break if Exception were a new-style class. We cannot make the change except when we declare an "incompatible change". The reason for making the change to new-style classes throughout is to simplify Python's design (and the model the user must have in his head). > Us non C programmers look forward to PyPy for the view of the netherworld it > will > give us. In truth I expect PyPy to bring a new burst of creative energy to > the > Python world, just by opening up the possibility of lower level exploration > to > a wider group of folks. > > As the answer to most of the "why Python" questions that we all try to answer > on some technical level, in the end - IMO - boil done to largely that, the > creative > energy surrounding it. > > Perhaps that understanding should provoke me into whining less about the > moving > target that Python seems sometimes to be. Perhaps Guido understands either > consciously or > intuitively that less openness to change - with all the downsides of such > change - > would subvert that essential energy aura in which Python persists. --Scott David Daniels [EMAIL PROTECTED] ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Scott David Daniels wrote: >Arthur wrote: > > >>My studies on the subject of subclassing the complex type have been quickly >>abandoned - it becoming clear that the fact the .real and .imag are read-only >>defeats the ideas I had for it. >> >> >Ahh: complex is (as are bool, int, long, string, and unicode) immutable. >Changing such types to be mutable is "nasty" -- reuse of an immutable is >done by referring to the same object, while reuse of an immutable needs >a copy. > Getting one's arms around all the practical implications of these issues related to mutable, immutable - understanding when one should want to retain object identity, and when one should want to break it, the full implications of these decisions, howto implement one's intentions - is, on one hand - I find, fundamental to getting things to actually happen in Python as one intends, and on the other hand , challenging. It is the fundamental reason I chafe a bit when Python is described as "easy". Because I have had trouble with these issues from day one, it ain't day one anymore, I still have some troubles with them and I prefer to think that it is challenging over thinking that I am dumb. I am going down the road of the mutable complex number with my eyes (half) open precisely because I want the ability to change the value of a complex number object (and it's subclasses), without changing the identity of the object. Is that so wrong ;) >If you define a class named PyGeoTriangle, you create new instances with >PyGeoTriangle(). > The connection of what you are saying here to the issue on which I am particularly confused is - well - confusing, to me. In Arthur's head there is the numeric type "float", and there is the function float() - both built in. And in Arthur's head, while functions are first class objects in Python they are objects of a different nature than type in the sense of numeric type. So in some sense what I am not grasping is how class/type unification can be inclusive of verb - i.e, float(1) - and noun - i.e., type(1.) - unification - which in Arthur's head, is something else again. Art ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
> Kirby > > PS: since you've been studying subclassing primitive types using __new__, > maybe you could show us a user-defined floating point type that reports > two numbers equal if their absolute value difference is less than e. > Anyone? > Like this I guess: >>> class Fuzzy(float): tol = 1e-8 def __new__(cls, arg=0.0): return float.__new__(cls, arg) def __eq__(self, other): if abs(self-other)>> j = Fuzzy(10) >>> type(j) >>> k = Fuzzy(10.1) >>> j == k True >>> k = Fuzzy(10.01) >>> j == k False Kirby ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Kirby Urner wrote: >>Kirby >> >>PS: since you've been studying subclassing primitive types using __new__, >>maybe you could show us a user-defined floating point type that reports >>two numbers equal if their absolute value difference is less than e. >>Anyone? >> > Fuzzy redone a breath: class Fuzzy(float): tol = 1e-8 def __new__(cls, arg=0.0): return float.__new__(cls, arg) def __eq__(self, other): return abs(self - other) < self.tol > ... Here's the problem: Your notion of equality is not transitive. That's tough -- it invalidates the assumptions of the float type (and all basic types). Also, you didn't tweak hash, so a dictionary with these things in them would not find entries that turn out to be equal. --Scott David Daniels [EMAIL PROTECTED] ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
> Here's the problem: > Your notion of equality is not transitive. That's tough -- it > invalidates the assumptions of the float type (and all basic types). > Also, you didn't tweak hash, so a dictionary with these things in them > would not find entries that turn out to be equal. > > --Scott David Daniels > [EMAIL PROTECTED] Yes, good tweak, and fair warnings (GvR warned me earlier). Fuzzy is no doubt pretty useless, plus I solved my earlier problem a different way. This thread has been helpful nonetheless. I've learned more __python__. Kirby ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Arthur wrote: > Scott David Daniels wrote: > ... > Getting one's arms around all the practical implications of these issues > related to mutable, immutable - understanding when one should want to > retain object identity, and when one should want to break it, the full > implications of these decisions, howto implement one's intentions - > is, on one hand - I find, fundamental to getting things to actually > happen in Python as one intends, and on the other hand , challenging. It > is the fundamental reason I chafe a bit when Python is described as "easy". Ah, but you are concentrating on fundamental issues of language design which are, in fact, subtle. Normally the user of a language simply accepts the determination of the designer about what is mutable and what is not, and goes on from there. I think these issues are indeed fascinating, but they are issues of language design, not even issues for the __python__ class. Python allows you to play with these issues in your own classes, few other languages allow you that freedom. > Because I have had trouble with these issues from day one, it ain't day > one anymore, I still have some troubles with them and I prefer to think > that it is challenging over thinking that I am dumb. Well, you are right. > I am going down the road of the mutable complex number with my eyes > (half) open precisely because I want the ability to change the value of > a complex number object (and it's subclasses), without changing the > identity of the object. In the first Fortran (and for a number of versions later), you called "subroutines" with all arguments "by reference." There were people who would abuse this ability to change constants (which were shared across a single "compilation unit") to find compact ways to alter things that were not properly variables. This brings new meaning to "1+1=4 for sufficiently large values of 1". >>If you define a class named PyGeoTriangle, you create new instances with >>PyGeoTriangle(). > > The connection of what you are saying here to the issue on which I am > particularly confused is - well - confusing, to me. I'm trying to point out that you understand perfectly that some things are both objects and callable; you just don't realize that you do. The most obvious example is a class, while the second (and far less) obvious is an instance of a class with a __call__ method. In the case of a class that you have defined, you can use the class name itself in calls to things like "isinstance," > In Arthur's head there is the numeric type "float", and there is the > function float() - both built in. And in Arthur's head, while > functions are first class objects in Python they are objects of a > different nature than type in the sense of numeric type. > So in some sense what I am not grasping is how class/type unification > can be inclusive of verb - i.e, float(1) - and noun - i.e., type(1.) > - unification - which in Arthur's head, is something else again. The magic trick of class / type unification is: we both need to name types (they must have existence as objects) for use in some functions, and we need to provide constructors for instances of that type. This is the same situation we are in about classes. The class situation is resolved by making "special" methods that get invoked when the class is used to call --Scott David Daniels [EMAIL PROTECTED] ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
> -Original Message- > From: [EMAIL PROTECTED] [mailto:edu-sig- > [EMAIL PROTECTED] On Behalf Of Kirby Urner > Sent: Sunday, October 23, 2005 8:30 PM > To: 'Scott David Daniels'; edu-sig@python.org > Subject: Re: [Edu-sig] python versus __python__ > > Fuzzy is no doubt pretty useless, plus I solved my earlier problem a > different way. > > This thread has been helpful nonetheless. I've learned more __python__. Funny the connection. We're both going off doing useless things with numeric builtins, and playing around to try to solve some perceived "identity crisis". Just very different kinds of ones. Art ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Scott David Daniels wrote: > By the way, before you get too involved in playing with this stuff, > there is a nasty surprise waiting to bite you. When you are comparing > ids, be sure to compare ids of named things, not expressions. You might > be surprised to learn: id(math.log(math.pi)) == id(math.log(math.e))! > It is fun to try to figure out why. I'll post the answer tomorrow if > nobody gets it by then. With CPython, expressions, once used and dereferenced, recycle their objects. If you don't hold a reference to the value created by calculating the log of pi, it will get recycled once id is done with is arg. The available storage is lying around when log(e) is calculated and so is reused. Such things don't happen when working with small integers, because Python caches them to save some creation time. So, id(math.pi + 1.0) == id(29. / 7.) but then again: id(math.pi + 5280.0) == id(1. / 9.) --Scott David Daniels [EMAIL PROTECTED] ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
On Mon, 2005-10-24 at 20:24 -0700, Scott David Daniels wrote: > With CPython, expressions, once used and dereferenced, recycle their > objects. If you don't hold a reference to the value created by > calculating the log of pi, it will get recycled once id is done > with is arg. The available storage is lying around when log(e) > is calculated and so is reused. Such things don't happen when > working with small integers, because Python caches them to save > some creation time. > > So, > id(math.pi + 1.0) == id(29. / 7.) > > but then again: > id(math.pi + 5280.0) == id(1. / 9.) > Neat :-) Of course, the proper way to compare object identity is not the __low_level__ `id()` function but the ``is`` operator: >>> (math.pi + 1.0) is (29. / 7.) False >>> int('99') is int('99') # small integer True >>> int('100') is int('100') # big integer False [``is`` works properly because both expressions are evaluted before the ``is`` operator is evaluted and only then the 2 values are garbage-collected. With `id()`, the 2 values could be reclaimed immediately because only the address is needed for the ``==`` comparison. The fact that `id(foo)` does not reference `foo` is the #1 source of confusion regarding `id()`.] ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Re: [Edu-sig] python versus __python__
Beni Cherniavsky wrote: > On Mon, 2005-10-24 at 20:24 -0700, Scott David Daniels wrote: > > Of course, the proper way to compare object identity is not the > __low_level__ `id()` function but the ``is`` operator: > (math.pi + 1.0) is (29. / 7.) > > False > int('99') is int('99') # small integer > > True > int('100') is int('100') # big integer > > False > > [``is`` works properly because both expressions are evaluted before the > ``is`` operator is evaluted and only then the 2 values are > garbage-collected. With `id()`, the 2 values could be reclaimed > immediately because only the address is needed for the ``==`` > comparison. The fact that `id(foo)` does not reference `foo` is the #1 > source of confusion regarding `id()`.] That won't save you from surprises when walking in subtle territory. For example: # Distributive law >>> -(-3 - 7) is (- -3) - -7 True But: >>> -(3 + 7) is -3 - -7 False The difference is the aforementioned caching trick -- small positive (and a few negative) integers are cached, the exact range is, I think -5 : 100, but it is subject to change and should _not_ be remembered (Python is free to change the number at any time; caching is an optimization, not meant to affect the meaning of the language). In general the "is" operator is asking about internals you should seldom be poking around inside (playing with magic) except for the incantation "is None" and "is not None" since there is one and only one None. There are, of course, times when you are concerned about "exactly this object" and those times are when is is proper, (and id(obj) might well be a perfectly fine value supplying a total order on such objects). The main reason I am belaboring the point is the recent mutable / immutable discussion: you should never concern yourself with the identity of an immutable; they are "values" to be compared using equality or ordering comparisons. Two immutables built the same way should be indistinguishable from two references to the same immutable in properly written code. You need immutables for dictionary keys, because (in the implementation) structure is built based on values of the keys. If the values changed by mutating, your structure would no longer reflect the values it contains (so some data would become unreachable). storage = {3+4j : 1, 4+3j : 2} Suppose you negated the imaginary part of the object which is the key to the value 1. What should storage[3+4j] (where 3+4j is freshly calculated) return? What should storage[3-4j] (where 3-4j is freshly calculated) return? Such problems are not so much implementation issues (although they do reveal the implementation) as problems with the definition of the language. That's why this is subtle territory. --Scott David Daniels [EMAIL PROTECTED] ___ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig