%%deffont "standard" tfont "Arial.ttf" %%deffont "thick" tfont "Arial_Bold.ttf" %deffont "standard" tfont "tahoma.ttf" %deffont "thick" tfont "tahomabd.ttf" %deffont "typewriter" tfont "Andale_Mono.ttf" %default 1 area 90 90, leftfill, size 2, fore "white", back "black", font "thick" %default 2 size 7, vgap 10, prefix " " %default 3 size 2, bar "gray70", vgap 10 %default 4 size 2, vgap 10, prefix " " %default 5 size 5, fore "white", vgap 30, prefix " ", font "standard" %tab 1 size 5, vgap 40, prefix " ", icon box "green" 50 %tab 2 size 4, vgap 40, prefix " ", icon arc "yellow" 50 %tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40 %page New stuff in Python 2.2 Easy stuff Iterators Generators classmethod() and staticmethod() Descriptors Properties Type/class unification __new__ __slots__ Metaclasses Secret-bonus section: Python 2.3 %page Easy stuff %cont, font "typewriter", size 4 import this %font "standard" int vs. long %font "typewriter", size 2 %font "typewriter", size 4 > >> import sys > >> sys.maxint 2147483647 > >> sys.maxint + 1 2147483648L > >> # No overflow! %font "standard" True and False These will be real bools in 2.3, for now they're just 1 and 0. %page Iterators Iterators are objects for accessing the items of sequence, one element at a time. You usually use them in a for loop. Example: Files are now iterators %font "typewriter", size 2 %font "typewriter", size 4 for line in open('/etc/passwd'): # do something with line %font "standard" New builtin, %cont, font "typewriter" iter %font "standard" %font "typewriter", size 2 %font "typewriter", size 4 > >> iter(open('/etc/passwd')) %font "standard" %page Using Iterators You can also use iterators directly, without a for loop: %font "typewriter", size 2 %font "typewriter", size 4 > >> i = iter(range(3)) > >> i > >> i.next() 0 > >> i.next() 1 > >> i.next() 2 > >> i.next() Traceback (most recent call last): File " ", line 1, in ? StopIteration > >> %font "standard" %page Writing your own Iterator Implement %cont, font "typewriter" __iter__ %cont, font "standard" on your class It should return an object with a %cont, font "typewriter" .next() %cont, font "standard" method Raise %cont, font "typewriter" StopIteration %cont, font "standard" when done (if ever) Generators make this easy... %page Generators These are my favourite addition to 2.2 Generators are resumable functions Generators implement the Iterator protocol Example from PEP 255: %font "typewriter", size 2 %font "typewriter", size 4 from __future__ import generators def fib(): a, b = 0, 1 while 1: yield b a, b = b, a+b %font "standard" %page fib in action Example %font "typewriter", size 4 > >> g = fib() > >> g > >> g.next() 1 > >> g.next() 1 > >> g.next() 2 > >> g.next() 3 > >> g.next() 5 > >> g.next() 8 > >> g.next() 13 %font "standard" %page fib in action again Another example %font "typewriter", size 4 > >> g = fib() > >> for n, f in zip(range(10), g): print n, f ... 0 1 1 1 2 2 3 3 4 5 5 8 6 13 7 21 8 34 9 55 %font "standard" %page Generators explained Any function with a " %cont, font "typewriter" yield %cont, font "standard" " statement automagically is a generator function Calling a generator function creates an instance of that generator -- but nothing happens yet Calling %cont, font "typewriter" .next() %cont, font "standard" on the resulting generator runs the function as normal If the generator %cont, font "typewriter" return %cont, font "standard" s or %cont, font "typewriter" raise %cont, font "standard" s StopIteration, it finishes If it %cont, font "typewriter" yield %cont, font "standard" s a value, it returns that value to the caller of %cont, font "typewriter" .next() %cont, font "standard" , but remembers where it stopped, and what all the local variables were Calling %cont, font "typewriter" .next() %cont, font "standard" again continues from where it stopped... %page Generators continued Because they preserve their state between calls, you can many different generators instatiated at once They tend to be a very convenient way to implement Iterators: %cont, font "typewriter" __iter__ %cont, font "standard" can simply return a generator. %page staticmethod Like static methods in C++ and Java Example: %font "typewriter", size 4 > >> class C: ... def foo(x, y): # No self! ... print 'static method foo:', x, y ... foo = staticmethod(foo) ... > >> C.foo(1,2) static method foo: 1 2 > >> c = C() > >> c.foo(1,2) static method foo: 1 2 %font "standard" %page classmethod Sort of inbetween static methods and normal methods Example: %font "typewriter", size 4 > >> class C: ... def foo(cls, x, y): ... print 'class method foo:', cls, x, y ... foo = classmethod(foo) ... > >> C.foo(1,2) class method foo: __main__.C 1 2 > >> c = C() > >> c.foo(1,2) class method foo: __main__.C 1 2 > >> class D(C): pass ... > >> D.foo(1,2) class method foo: __main__.D 1 2 %font "standard" %page How does staticmethod work? Here's a pure Python implementation: %font "typewriter", size 4 > >> def smethod(x): ... class staticmethod(object): ... def __init__(self, x): ... self.x = x ... def __get__(self, obj, class_=None): ... # Always return an unmolested object ... return self.x ... return staticmethod(x) ... > >> # Test it > >> class C: ... def f(x,y): print 'f', x, y ... f = smethod(f) ... > >> C.f(1,2) f 1 2 > >> C().f(1,2) f 1 2 %font "standard" %page So what the hell is __get__?! I'm glad you asked ;) This is the same mechanism that magically: makes functions in classes into unbound methods, and functions in instances into bound methods. Part of the "Descriptor" protocol %page Descriptors continued This: %font "typewriter", size 4 instance.attribute %font "standard" Actually calls this: %font "typewriter", size 4 attribute.__get__(instance, instance.__class__) %font "standard" And this: %font "typewriter", size 4 MyClass.attribute %font "standard" Actually calls this: %font "typewriter", size 4 attribute.__get__(None, MyClass) %font "standard" There's also %cont, font "typewriter", size 4 __set__ %cont, font "standard" and %cont, font "typewriter", size 4 __delete__ %cont, font "standard" . %page Properties Properties are a nice way create attributes that look like attributes, but actually call functions when used. Example: %font "typewriter", size 4 class C(object): def __init__(self): self.__x = 0 def getx(self): return self.__x def setx(self, x): if x < 0: x = 0 self.__x = x x = property(getx, setx) %font "standard" %page Properties continued Using the example: %font "typewriter", size 4 > >> a = C() > >> a.x = 10 > >> print a.x 10 > >> a.x = -10 > >> print a.x 0 > >> a.setx(12) > >> print a.getx() 12 > >> %font "standard" Full prototype is: property(fget=None, fset=None, fdel=None, doc=None) Doesn't work for classic classes %page But hang on a second! %pause What's a "classic" class? %pause And what is a "new-style" class? %pause And why have some of the examples had code like: %font "typewriter", size 2 %font "typewriter", size 4 class Foo(object): # What the hell is "object"?! %font "standard" %pause I'm glad you asked! :) %page Type/Class unification In Python 2.2, types, (things like int, str and dict) are now more like classes. You can subclass from the builtin types! More elegant: No more need for UserDict and UserList modules. And faster! Guido says: "This is one of the biggest changes to Python ever" %page Subclassing builting types Example: a simple dict subclass that provides a "default value" that is returned when a missing key is requested %font "typewriter", size 2 %font "typewriter", size 4 class defaultdict(dict): def __init__(self, default=None): dict.__init__(self) self.default = default def __getitem__(self, key): try: return dict.__getitem__(self, key) except KeyError: return self.default %font "standard" %page Builtin types are classes Existing builtins str, int, float, long, complex, list and tuple are now effectively classes dict and file have been added to the builtins Just like a class, you call them to construct an object of that type this is completely backwards compatible with how it used to work Pleasant side-effect: you can now do %font "typewriter", size 2 %font "typewriter", size 4 > >> l = [1,2,3] > >> if type(l) is list: print 'yep' ... yep > >> # No need to use types.ListType! %font "standard" %page object and type New builtin: %cont, font "typewriter" object %font "standard" %cont, font "typewriter" object %cont, font "standard" is the base class of new style objects %font "typewriter", size 2 %font "typewriter", size 4 class C(object): """I am a new-style class, because I inherit from object""" %font "standard" New builtin: %cont, font "typewriter" type %font "standard" %cont, font "typewriter" type %cont, font "standard" is a subclass of %cont, font "typewriter" object %cont, font "standard" , and is the type of all builtin types. %font "typewriter", size 2 %font "typewriter", size 4 > >> object, type, int ( , , ) > >> object.__bases__, type.__bases__, int.__bases__ ((), ( ,), ( ,)) > >> type(object), type(type), type(int) ( , , ) %font "standard" %page Subclassing immutable types Problem: __init__ is called *after* an object is allocated. immutable types' contents are already set in stone by __init__ %font "typewriter", size 2 %font "typewriter", size 4 > >> class SquaringTuple(tuple): ... def __init__(self, *args): ... tuple.__init__(self, [x**2 for x in args]) ... > >> t = SquaringTuple(1, 2, 3) Traceback (most recent call last): File " ", line 1, in ? TypeError: tuple() takes at most 1 argument (3 given) %font "standard" %page __new__ Solution: __new__, which is called to allocate the object %font "typewriter", size 2 %font "typewriter", size 4 > >> class SquaringTuple(tuple): ... def __new__(cls, *args): ... return tuple.__new__(cls, [x**2 for x in args]) ... > >> t = SquaringTuple(1, 2, 3) > >> t (1, 4, 9) %font "standard" __new__ is called with a class as its first argument; its responsibility is to return a new instance of that class Compare this to __init__: __init__ is called with an instance as its first argument, and it doesn't return anything; its responsibility is to initialise the instance %page __new__ continued __new__ could return a cached instance of a class __new__ can return an instance of a completely different class! But you need Python 2.2.2 if you want the right __init__ to be called %page __slots__ Normally, every object instance has a __dict__ attribute -- a complete dictionary object. This is often unnecessary -- e.g when subclassing dict! The defaultdict class from earlier would take twice the memory of a plain dict Solution: You can define a __slots__ attribute on new-style classes it reserves space for the attributes named in it, and only those attributes no __dict__ is allocated %page __slots__ continued Example %font "typewriter", size 2 %font "typewriter", size 4 > >> class C(object): ... __slots__ = ['x', 'y'] ... > >> c = C() > >> c.x = 1 > >> c.x 1 > >> c.z = 2 Traceback (most recent call last): File " ", line 1, in ? AttributeError: 'C' object has no attribute 'z' %font "standard" %page Metaclasses "In the past, the subject of metaclasses in Python has caused hairs to raise and even brains to explode" %pause "Fortunately, in Python 2.2, metaclasses are more accessible and less dangerous" %pause This is going to be a really brief peek at metaclasses. There just isn't enough time to discuss them properly in this talk. %pause What defines a class? Name, base classes, and its namespace (a dict) %page Metaclasses in 1 easy slide %font "typewriter", size 4 > >> class capitalise(type): ... def __init__(cls, name, bases, dict): ... type.__init__(cls, name, bases, dict) ... for name in dict: ... NAME = name.upper() ... if NAME not in dict: ... setattr(cls, NAME, dict[name]) ... > >> class C: ... __metaclass__ = capitalise ... def foo(self): ... print 'foo' ... > >> c = C() > >> c.foo() foo > >> c.FOO() foo %font "standard" %page Secret-Ultra-Mega Bonus: Python 2.3 enumerate %font "typewriter", size 2 %font "typewriter", size 4 > >> s = "Hello from Guido's time machine!' > >> for index, word in enumerate(s.split()): ... print index, word ... 0 Hello 1 from 2 Guido's 3 time 4 machine! %font "standard" faster list sorting A standard Set module This may eventually become a builtin %page Python 2.3 continued Extended slices %font "typewriter", size 2 %font "typewriter", size 4 > >> range(10)[::-2] [9, 7, 5, 3, 1] %font "standard" A standard logging module Universal Newline support can automatically convert all line endings into \n Lots of little optimisations Benchmarks suggest that 2.3 is about 25% faster! And lots more! Not as insanely action-packed as 2.2, though ;) %page Links %font "typewriter" http://python.org/2.2.2/descrintro.html http://python.org/doc/2.2.1/whatsnew/ %font "standard" Questions?