advanced python

22
ADVANCED PYTHON by Gyuri Horak

Upload: eu-edge

Post on 06-Jul-2015

311 views

Category:

Software


5 download

TRANSCRIPT

Page 1: Advanced python

ADVANCED PYTHONby Gyuri Horak

Page 2: Advanced python

DIAMOND INHERITANCE PROBLEM

Cls.__mro__ - method resolution order

py> class A(object): passpy> class B(A): passpy> class C(A): passpy> class D(B,C): passpy> D.__mro__(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)

Page 3: Advanced python

MIXINS

You can add baseclasses runtime

class A(object): passclass B(object): passclass C(A): pass

py> C.__bases__ += (B,)py> C.__mro__(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)

Page 4: Advanced python

VARIABLE SCOPE

● No declaration, just use any variable whenever you want

● There's global but ...● Namespaces are dicts● module.submodule.variable = 42

● del keyword● __builtins__, locals()

Page 5: Advanced python

VARIABLE SCOPEdef scopetest(mut, imut): global gvar gvar = 11 lvar = 12 mut += [2] imut += "apple" print locals() # {'mut': [1, 2], 'lvar': 12, 'imut': 'pineapple'}

gvar, lvar, amut, aimut = 1, 1, [1], "pine"print locals()# {'__builtins__': <..>, 'scopetest': <function ..>,# '__file__': 'scope.py', 'amut': [1], 'gvar': 1,# '__package__': None, 'lvar': 1, 'aimut': 'pine',# '__name__': '__main__', '__doc__': None}scopetest(amut, aimut)print locals()# {'__builtins__': <..>, 'scopetest': <function ..>,# '__file__': 'scope.py', 'amut': [1, 2], 'gvar': 11,# '__package__': None, 'lvar': 1, 'aimut': 'pine',# '__name__': '__main__', '__doc__': None}

Page 6: Advanced python

ITERATORS

● container.__iter__() -> iterator● iterator.__iter__() -> iterator (self)● iterator.next() -> next item, or StopIteration

exception

py> a = [1,2,3,4,5]py> i = a.__iter__()py> i.next()1py> i.next()2

Page 7: Advanced python

GENERATORS, YIELD

Generate the next item only when we need it

class Fib(object): def __init__(self, limit): self.limit = limit def __iter__(self): p0, p = 0, 1 # tuple pack/unpack while p < self.limit: yield p p0, p = p, p+p0 raise StopIteration

py> f100 = Fib(100)py> for x in f100:... print x,1 1 2 3 5 8 13 21 34 55 89

Page 8: Advanced python

LIST COMPREHENSIONS

The functional way of list creation

py> [x+1 for x in f100][2, 2, 3, 4, 6, 9, 14, 22, 35, 56, 90]

In Python 3 dicts and sets can be created this way as well

Page 9: Advanced python

ITERTOOLS

Useful toolset for iterators

py> from itertools import izippy> for x,y in izip(xrange(10), f100):... print "(%s, %s)" % (x, y),(0, 1) (1, 1) (2, 2) (3, 3) (4, 5) (5, 8) \(6, 13) (7, 21) (8, 34) (9, 55)

Page 10: Advanced python

COROUTINES (PEP-342)def grep(pattern): print "Looking for %s" % pattern while True: line = (yield) if pattern in line: print line

py> g = grep("python")py> g.next()py> g.send("No snakes here.")py> g.send("Generators in python ROCK!")Generators in python ROCK!py> g.close()

Page 11: Advanced python

OPERATOR OVERLOADINGclass Fun(object): def __init__(self, function): self.function = function def __call__(self, *args, **kwargs): return self.function(*args, **kwargs) def __add__(self, funinst): def inner(*args, **kwargs): return funinst(self.function(*args, **kwargs)) return Fun(inner)

py> f1 = Fun(a)py> f1(1,2) # 3py> f2 = Fun(lambda x: x*x)py> f2(2) # 4py> f3 = f1+f2py> f3(1,2) # 9

Page 12: Advanced python

__gettattr__class JSObj(dict): def __getattr__(self, attr): return self.get(attr) def __setattr__(self, attr, value): self[attr] = value

py> o = JSObj({'a': 10, 'b': 20})py> o.a # 10py> o.c # Nonepy> o.c = 30py> o['c'] # 30py> o.c # 30

Page 13: Advanced python

__dict__class Borg(object): __shared_state = {} def __init__(self): self.__dict__ = self.__shared_state

py> a = Borg()py> b = Borg()py> a.x = 42py> b.x42py> a == bFalse

http://docs.python.org/reference/datamodel.html#special-method-names

Page 14: Advanced python

NOTHING IS PRIVATE (AGAIN)def hide(o): class Proxy(object): __slots__ = () def __getattr__(self, name): return getattr(o, name) return Proxy()

class A(object): a = 42

py> a = hide(A())py> a.a42py> a.a = 43AttributeError: 'Proxy' object has no attribute 'a'

py> a.__getattr__.func_closure[0].cell_contents<__main__.A object at 0x7faae6e16510>

Page 15: Advanced python

DECORATORS● syntactic sugar● class decorators in Python 3● functool.wraps helper - sets __name__, docstring, etc.● @classmethod, @staticmethod

def funct(): passfunct = decorator(funct)

@decoratordef funct(): pass

Page 16: Advanced python

EXAMPLE DECORATORdef logger(f): def inner(*args, **kwargs): print "%s called with arguments: %s; %s" % (f.__name__, args, kwargs) retval = f(*args, **kwargs) print "%s returned: %s" % (f.__name__, retval) return retval return inner

@loggerdef mul(a,b): return a*b

py> mul(1,2)mul called with arguments: (1, 2); {}mul returned: 2

Page 17: Advanced python

DESCRIPTORS● to "hide" getter/setter methods

○ __get__(self, instance, owner)○ __set__(self, instance, value)○ __delete__(self, instance)

● functions are descriptors (with __get__), late binding is possible

Page 18: Advanced python

PROPERTIESclass PropEx(object):

__a = 1 __b = 2

@property def c(self): return self.__a + self.__b

def getA(self): return self.__a def setA(self, value): self.__a = value def delA(self): self.__a = 1

a = property(getA, setA, delA) # @property, @m.setter, @m.deleter

py> x = PropEx()py> x.a = 12py> x.c14py> x.__class__.__dict__['a'].fset<function setA at 0x7ff241c266e0>

Page 19: Advanced python

FUNCTIONS / METHODSdef myclass(self): return self.__class__

class A(object): def method(self): pass

py> a = A(); a.__class__.__dict__['method']<function method at 0x7ff241c26cf8>py> a.__class__.method<unbound method A.method>py> a.method<bound method A.method of <__main__.A object at 0x7ff242d56bd0>>py> a.myclass = myclass; a.myclass()TypeError: myclass() takes exactly 1 argument (0 given) # ???py> a.myclass<function myclass at 0x7ff241c26b18> # :(py> a.myclass = myclass.__get__(a, A); a.myclass()<class '__main__.A'>py> a.myclass<bound method A.myclass of <__main__.A object at 0x7ff242d56bd0>> # :)

Page 20: Advanced python

type()● function: returns the type of the argument● but it's a type too● moreover it's the root of all classes

py> type(object)<type 'type'>py> type(type)<type 'type'>

● AND it can create new classes runtime

Page 21: Advanced python

METAPROGRAMMINGdef constr(self): print "new instance created" self.foo = "foo"

def method(self): print "foo: " + self.foo

py> MyClass = type("MyClass", # classname (dict, object), # baseclasses {'PI': 3.14, # __dict__ 'method': method, '__init__': constr})py> myinstance = MyClass()new instance createdpy> myinstance.method()foo: foo

Page 22: Advanced python

__metaclass__When defined, it is called instead of type at class generation

class mymeta(type): def __new__(mcs, name, bases, dict): dict['myprop'] = 'metaclass property' return type.__new__(mcs, name, bases, dict)

class A(object): __metaclass__ = mymeta

py> a = A()py> a.myprop'metaclass property'

You can do _anything_ here, like type checking based on docstrings (or py3 annotations), decorating all the methods, create mixins ...