Re: comparison with None
On Thursday 19 April 2007, Steven Howe wrote: > > ((int(3) > int(4)) == True) == True > > > > Explicit is better than sensible, yes? > > > > *wink* > > Your example, even with the *wink*, is stupid. The language requires 3 > to be an integer, 4 to be an integer. Incidentally, the language also requires that None be unique (and the only object of type NoneType). I believe that the point of the 'example' was to show that because of the language's guarantees, both are equally pointless. > > > The point I was show is with respect to a returned variable (like from a > function or method? *wink* *wink*). > For example, if you expect an open file handle, but get a NoneType > because you didn't really open a file (having given a bad name or maybe > didn't have permission to open a file), then it would be best to test > the type of return object before using it. Then you program could handle > the error gracefully (*wink* *wink* *wink*). You don't get "a NoneType", you get None, the unique instance of NoneType. A function cannot return and object of type NoneType without it being None. Here's what happens if you try: >>> from types import ListType >>> ListType() [] >>> from types import NoneType >>> NoneType() Traceback (most recent call last): File "", line 1, in TypeError: cannot create 'NoneType' instances > As much as I love Python, it's ability to morph an object type can be a > pain. Testing before using can prevent a program from Error-ing out. Well, the thing is, that's kind of the point. In Python, type is supposed to be irrelevant. That's the idea of "duck typing". If I need to do o.quack(), I can do two things to handle the error gracefully: check if it had the quack method ("hasattr"), or catch the exception. Checking "type(o)==Duck" is wrong almost all the time. If I subclass Duck (to, say a species), it'll likely still be an appropriate object, but then type(o)!=Duck. And what if I want to use a DucklikeGoose? In that case, even "isinstance(o, Duck)" would be False, but it still implements an appropriate "quack" method. Finally, you had said before: > I love scripting languages ... but sometimes an explicit evaluation that > one would find in a compiled language is better. > Which is why I suggested using the explicit type(x) == types.NoneType as > opposed to > x is None I'll sidestep the issue of Python begin compiled to VM code (think Java)... How would you do thing in compiled code? In C, functions that return pointers indicate errors by returning NULL. Supposing you had a function that would determine the type of a pointer, would you use "type(p)==TYPE_NONE" or "p==NULL"? In Python, the "is" operator basically compares pointers, so saying "p is q" would tanslate to "p==q" in C (supposing p and q are pointers to objects). At the end of the day, "type(x) == types.NoneType" is going to be true if and only if "x is None". So, whichever way you do it is up to you, though FWIW the latter line is: Faster: No need for type() call, lookup in types Smaller: No need for types module Shorter Clearer: "is None" shows very clear intent -- http://mail.python.org/mailman/listinfo/python-list
Re: Python un-plugging the Interpreter
On Thursday 19 April 2007, S.Mohideen wrote: > 2) Making the program to run at par with the compiled version of C/C++ > program- this is the main benefit which can be derived out of this. Python is a rather slow language because of how it works. Even if you got rid of the VM (as noted by others, Python compiles into VM code), Python would still be slower than C, and probably by a large margin. Look at the "+" operator for instance. In C, this translates directly to and add instruction that takes something like 1 cycle. Very fast. In python, it translates (very) roughly to: def add(a,b): if issubclass(b,a): try: return b.__dict__['__radd__'](a) catch: return a.__dict__['__add__'](b) else: try: return a.__dict__['__add__'](b) catch: return b.__dict__['__radd__'](a) So for 2+2, you'll have to go through "issubclass", then look up '__add__' from 2.__dict__ (it's there), then execute the function before you finally get to the "add" instruction. So ultimately, you pay for he flexibility. Sure, you can kind of optimize builtin operations (like "2+2"), but even with something like a 'PPU' (Python Processing Unit) that had hardware dictionary support (<5ish cycles per lookup) you'll still be an order of magnitude off C easily. It's not hopeless though. With an insanely clever JIT VM and lots of caching, it could be possible to get Python within an order of magnitude of C, but the demand isn't really there. Things that need to be fast can be written easily enough in C libraries. I think Pypy, which is an implementation of Python in Python, may be headed in that direction (clever JIT), but it's a long way off to say the least. -- http://mail.python.org/mailman/listinfo/python-list
Re: Better dict of dicts
On Thursday 19 April 2007, Bill Jackson wrote: > I have a dictionary of dictionaries where the keys are typically very > long tuples and repeated in each inner dictionary. The dictionary > representation is nice because it handles sparseness well...and it is > nice to be able to look up values based on a string rather than a > number. However, since my keys are quite long, I worry that I am > wasting a lot of memory. I'm looking for better data structures. I think you may want to look into that rarely used function "intern" (under "on-essential Built-in Functions"). Basically, Python keeps a cache of certain strings are are frequently used so comparisons and dictionary lookups only require a pointer comparison. You could then subclass dict (though using "DictMixin" could be better) like: class IDict(DictMixin): def __setitem__(self, key, value): key=intern(key) self.__dict[key]=value That's totally untested and incomplete, but you hopefully get the idea. Python (or at least CPython) seems to auto intern some strings occasionally (you could look at the source if you care about the exact rules). Example: >>> a="1234567890" >>> b="1234567890" >>> a is b True So you don't have all that much to worry about. -- http://mail.python.org/mailman/listinfo/python-list
Re: Better dict of dicts
On Thursday 19 April 2007, Bill Jackson wrote: > Martin v. Löwis wrote the following on 04/19/2007 02:43 PM: > > Bill Jackson schrieb: > >> I have a dictionary of dictionaries where the keys are typically very > >> long tuples and repeated in each inner dictionary. > > > > What I don't understand here: you say the keys are tuples, yet later, > > you show that the keys are strings. Which one is it? > > Sorry, I was just lazy. The keys will always be tuples...tuple of > strings, tuples of numbers, tuples of objectssimply tuples. That'll change things a bit because intern only works with strings. Of course, It's not so big a deal, but you will have to put together a class to implement interning. I wrote one for fun: class ITuple(tuple): _interns={} def __new__(cls, tup): if tup not in cls._interns: itup=tuple.__new__(cls, tup) cls._interns[tup]=itup return cls._interns[tup] def __init__(self, *args): #Prevent multiple calls to __init__ if hasattr(self, "_inited"): return tuple.__init__(self, *args) self._inited=True def __eq__(self, o): #If the other is an ITuple, self==o iff self is o if isinstance(o, ITuple): return self is o return tuple.__eq__(self, o) >>> t1=(1,2,3,4); t2=(1,2,3,4) >>> ti1=ITuple(t1); ti2=ITuple(t2) >>> print t1==t2, t1 is t2 True False >>> print ti1==ti2, ti1 is ti2 True True That seems to work. Something to note is that the call overhead of the __eq__ function is large enough that unless you have a slow comparing tuple, comparisons will be faster without it. Comparisons are fast if they are done internally; so between builtin objects or identical (" is ") objects. For an example, suppose you have: class TTT(object): def __eq__(self, o): return True a,b=TTT(),TTT() Then the follow comparisons are fast: (1,2,3)==(1,2,3) (1,2,3,a)==(1,2,3,a) (0,0,0,a)==(1,2,3,b) The following are slow: (1,2,3,a)==(1,2,3,b) Note that the only slow case is the one where a.__eq__(b) is called. However, a.__eq__(b) is assumed True is "a is b" is True. So chances are you'll want to comment out the __eq__ function. -- http://mail.python.org/mailman/listinfo/python-list
Re: List of Objects
On Thursday 19 April 2007, [EMAIL PROTECTED] wrote: > Howdy, a (possibly) quick question for anyone willing to listen. > I have a question regarding lists and Classes; I have a class called > "gazelle" with several attributes (color, position, etc.) and I need > to create a herd of them. I want to simulate motion of individual > gazelles, but I don't want to have to go through and manually update > the position for every gazelle (there could be upwards of 50). I was > planning to create an array of these gazelle classes, and I was going > to iterate through it to adjust the position of each gazelle. That's > how I'd do it in C, anyway. However, Python doesn't support pointers > and I'm not quite sure how to go about this. Any help you can provide > would be greatly appreciated. > Thanks a lot! Actually, Python _only_ supports pointers: they're the names of objects. So for example, if I write x = Gazelle(...), then I create the name "x" that points to an instance of Gazelle. The storage for the instance is managed 'magically' by Python. If I were then to say "y = x", I'd also have a name "y" that points to the same instance. It's also worth noting that everything, including ints, strings and lists are objects as well. Because of this, a pointer to an object is the only storage class in python. Therefore, a name can point to any object of any type. As a result, an "array" in Python, which is commonly a list, is simply a list of pointers. They can point to strings, ints, other lists or anything. And because they store pointers, they can actually include themself! To demonstrate: >>> a=[1,'a',[1,2,3]] >>> for i in a: print i 1 a [1, 2, 3] >>> a.append(a) >>> for i in a: print i 1 a [1, 2, 3] [1, 'a', [1, 2, 3], [...]] Python's clever enough to not print out the circular reference. Finally, it's worth pointing out that in a language like this, where there are no arbitrary pointers (as there are in C), the pointer-to-object is called a reference. I just used "pointer" because you did ;). -- http://mail.python.org/mailman/listinfo/python-list
Re: Better dict of dicts
On Thursday 19 April 2007, Paddy wrote: > Martins earlier local_intern function would work for tuples as well as > strings. It certainly would. I had written that class, though, primarily to offer a performance improvement in the __eq__ and perhaps __hash__ methods. However, I ended up being rather surprised by just how much overhead there was in calling the Python methods vs. the builtin ones. So really mine only ends up being useful if the tuple consists of a couple (i.e. 2+) of objects with Python __eq__ methods. Oh well. As an interesting aside: >>> class A(object): ... def __eq__(self, o): ... return False ... >>> a=A() >>> a==a False >>> t=(a,) >>> t==t True Apparently the tuple's __eq__ assumes: "a is b" => "a==b" Bug? Or am I creating evil corner cases ;)? -- http://mail.python.org/mailman/listinfo/python-list
Re: That might be the case for more complex objects...
On Saturday 14 April 2007, James Stroud wrote: > I think that after a += 1, a memory location with a 6 is created and now > a points to that because += has assignment buried in it. Bingo. a+=1 will (basically) translate to either "a=a.__iadd__(1)" or "a=a.__add__(1)" depending on whether __iadd__ is defined of not. >>> '__iadd__' in dir(5) False >>> '__add__' in dir(5) True So therefore "a+=1" becomes "a=a.__add__(a, 1)" That make is relatively obvious that a '6' would be created and assigned back to a. You can have some fun with this using the 'is' operator. Remember that 'is' compares objects and not values. So different objects can be equal, but aren't the same. Thus: >>> a=[1,2,3] >>> b=[1,2,3] >>> a == b True >>> a is b False To demonstrate the idea of name binding: >>> a=500 >>> b=500 >>> a == b True >>> a is b False >>> b=a >>> a is b True So typing the literal '500' creates an integer object with the value 500. By typing it twice, two different objects of identical value are created and "put in" two variables. However, by assigning one from the other, the same object (created by the literal '500') is assigned to both variables. This is why Python calls assignments "bindings"; you're realling just binding the object from the right side to the name on the left. For confusion's sake, here's what happens if you use smaller numbers: >>> a=1 >>> b=1 >>> a is b True >>> 3-2 is a True That happens because CPython (a particular and very common implementation of Python) pre-creates objects for all small integers (something like <=100). This saves memory, because all values of '1' are the same! So the literal '1' simply gets a reference to the existing object of value '1', rather than creating a new one (like the literal '500' does). The same is also true for strings with len<=1. -- http://mail.python.org/mailman/listinfo/python-list