Chap 3 Python Object Oriented Programming - Copy.ppt
Meta-Classes in Python
1. Dynamic OOP and Meta-Classes in Python
Guy Wiener
Dept. of Applied Math and Computer Science
Weizmann Institute for Science
24/5/2011
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 1 / 57
2. Introduction
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
4 Examples
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 2 / 57
3. Introduction
What is OOP?
The OOP Manifest (abridged)
Alan Kay, 1993
Everything is an object
Computation is performed by objects communicating with each
other by sending and receiving messages
Each object has its own memory (state), which consists of other
objects.
Every object is an instance of a class.
The class is the repository for behavior. All instances of the
same class can perform the same actions.
Classes are organized into a singly rooted tree, called the
inheritance hierarchy.
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 3 / 57
4. Introduction
What is an object?
An object, according to the OOP manifest:
State Memory
Behavior Receiving and sending messages
Identity Each object is unique
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 4 / 57
5. Introduction
Objects Can Change!
Changing objects
State Read, write, add and remove field
Behavior Create, add and replace methods
Identity Remains the same
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 5 / 57
6. Introduction
Static Objects and Classes
Objects and Classes Example
Class A
Field descriptors x: int
Method desc. and code y: String
Hierarchy information foo() {. . . }
goo() {. . . }
Object
Run-time
Fields Instance of A
type infor-
content 5
mation
“hello”
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 6 / 57
7. Introduction
Dynamic Objects and Classes
Objects and Classes Example
Class A
A dictionary “foo” ⇒ {. . . }
of methods
“goo” ⇒ {. . . }
and static
fields
Instance of A
Object “x” ⇒ 5
A dictionary of “y” ⇒ “hello”
Class
fields and bound
pointer
methods
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 7 / 57
8. OOP Hacking
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
4 Examples
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 8 / 57
9. OOP Hacking
Everything is a Dictionary
Python’s modules, classes and objects = Dictionaries.
The dictionary holds:
Classes Methods and class variables
Objects Bound methods and fields
The “.” operator = Access the inner dictionary
The dir command = Lists keys of the inner dictionary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 9 / 57
10. OOP Hacking
Manipulating the Inner Dictionary
The inner dictionary is accessible and manipulable by string keys!
Inner dictionary manipulation
getattr(o, ’a’) Get the attribute a from the dictionary of o
setattr(o, ’a’, v) Set the attribute a of o to be v
obj.foo is same as getattr(obj, ’foo’)
obj.foo = val is same as setattr(obj, ’foo’, val)
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 10 / 57
11. OOP Hacking
Manipulating the Inner Dictionary (cont’d)
Example
>>> a = A()
>>> a.x = 5
>>> dir(a)
[..., ’x’]
>>> getattr(a, ’x’)
5
>>> setattr(a, ’x’, 6)
>>> a.x
6
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 11 / 57
12. OOP Hacking
Adding Fields
Adding fields to an object
class A: pass
>>> a = A()
>>> a.x = 5
>>> a.x
5
>>> setattr(a, ’y’, 6)
>>> a.y
6
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 12 / 57
13. OOP Hacking
Adding Fields
Adding fields to an object Gain & Loss
class A: pass Gained Flexible object content
>>> a = A() Lost Type safety
>>> a.x = 5
>>> a.x
5
>>> setattr(a, ’y’, 6)
>>> a.y
6
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 12 / 57
14. OOP Hacking
Replacing Methods
Swapping methods
class A:
def f(self):
print "f"
def g(self):
print "g"
>>> a = A()
>>> a.f, a.g = a.g, a.f
>>> a.f()
g
>>> a.g()
f
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 13 / 57
15. OOP Hacking
Replacing Methods
Swapping methods Gain & Loss
class A: Gained Change an object
def f(self): behavior at runtime
print "f" Lost Control flow analysis
def g(self):
print "g"
>>> a = A()
>>> a.f, a.g = a.g, a.f
>>> a.f()
g
>>> a.g()
f
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 13 / 57
16. OOP Hacking
Replacing Methods for a Class
Swapping class methods
class A:
def f(self):
print "f"
def g(self):
print "g"
>>> a = A()
>>> A.f, A.g = A.g, A.f
>>> a.f()
g
>>> a.g()
f
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 14 / 57
17. OOP Hacking
Replacing Methods for a Class
Swapping class methods Gain & Loss
class A: Gained Change a class at
def f(self): runtime
print "f" Lost Sanity
def g(self):
print "g"
>>> a = A()
>>> A.f, A.g = A.g, A.f
>>> a.f()
g
>>> a.g()
f
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 14 / 57
18. OOP Hacking
Classes are Return Values Too
A function that returns a class
def PersonClass(salut):
class Person(object):
def __init__(self, name):
self.name = name
def greet(self):
print salut, self.name
return Person
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 15 / 57
19. OOP Hacking
Classes are Return Values Too (cont’d)
Making classes Output
Man = PersonClass("Mr.") for c in a: c.greet()
Woman = PersonClass("Ms.")
Doctor = PersonClass("Dr.") >>> Ms. Rose Tylar
Ms. Amy Pond
a = [Woman("Rose Tylar"), Mr. Mickey Smith
Woman("Amy Pond"), Mr. Rory Williams
Man("Mickey Smith"), Dr. Who
Man("Rory Williams"),
Doctor("Who")]
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 16 / 57
20. Meta-Classes
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
4 Examples
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 17 / 57
21. Meta-Classes
What is Meta-Programming?
Meta-Program
A program that:
One of its inputs is a program (possibly itself)
Its output is a program
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 18 / 57
22. Meta-Classes
What is Meta-OOP?
Meta-Class
A class that creates classes
Objects are instances of classes
Classes are objects
Classes are instances of meta-classes
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 19 / 57
23. Meta-Classes
Object Systems
3-levels 4-levels
Object Object
A Class Type A Class Type
super: Type[]
super: Type[]
An Object
An Object
A MetaClass
Legend
instance of
extends
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 20 / 57
24. Meta-Classes Meta-Classes in Python
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
Meta-Classes in Python
4 Examples
Logging
Counting
Delegation
Associations
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 21 / 57
25. Meta-Classes Meta-Classes in Python
Meta-Classes in Python
The type class
Base class for meta-classes
Creates new classes
Dynamic members become static members of the instance class
type. init (cls, name, bases, dict)
cls The class object itself (i.e., “self”)
name The name of the class
bases A list of the base classes
dict A dictionary of the methods and static fields of the class
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 22 / 57
26. Meta-Classes Meta-Classes in Python
Creating Classes from Meta-Classes
Declaring a new class programatically
# Meta-Class
class Printable(type):
def whoami(self): print "I am ", self.__name__
>>> Foo = Printable(’Foo’,(),{}) # Empty new class
>>> Foo.whoami()
I am Foo
>>> Foo.__class__
<class ’Printable’>
>>> f = Foo() # Object
>>> f.__class__
<class ’Foo’>
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 23 / 57
27. Meta-Classes Meta-Classes in Python
The metaclass field
Class C is an instance of a meta-class M if:
1 C has a static field metaclass
2 One of the ancestors classes of C is an instance of M
3 There is a global variable metaclass
4 Otherwise, the default meta-class type is used
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 24 / 57
28. Meta-Classes Meta-Classes in Python
metaclass Example
Declaring a meta-class with metaclass
class Bar:
__metaclass__ = Printable
def foo(self): print ’foo’
>>> Bar.whoami()
I am a Bar
>>> b = Bar()
>>> b.foo()
foo
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 25 / 57
29. Examples
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
4 Examples
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 26 / 57
30. Examples Logging
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
Meta-Classes in Python
4 Examples
Logging
Counting
Delegation
Associations
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 27 / 57
31. Examples Logging
Logging with Meta-Classes
A logger decorator
def log(name, f):
def ret(*args):
print "enter", name
f(*args)
print "exit", name
return ret
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 28 / 57
32. Examples Logging
Logging with Meta-Classes (cont’d)
A logger meta-class
class Logged(type):
def init (cls, name, bases, dict):
type. init (cls, name, bases, dict)
p = re.compile(cls. logmatch )
for attr, item in dict.items():
if callable(item) and p.match(attr):
setattr(cls, attr, log(attr, item))
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 29 / 57
33. Examples Logging
Logging with Meta-Classes (cont’d)
A logged class
class Test:
metaclass = Logged
logmatch = ’.*’
def foo(self):
print ’foo’
>>> t = Test()
>>> t.foo()
enter foo
foo
exit foo
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 30 / 57
34. Examples Counting
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
Meta-Classes in Python
4 Examples
Logging
Counting
Delegation
Associations
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 31 / 57
35. Examples Counting
Counting Instances
Countable meta-class
class Countable(type):
def new_init(cls, init):
def ret(self, *args):
init(self, *args)
cls.count = cls.count + 1
return ret
def __init__(cls, name, bases, dct):
type.__init__(cls, name, bases, dct)
cls.count = 0
cls.__init__ = cls.new_init(cls.__init__)
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 32 / 57
36. Examples Counting
Counting Example
Some classes
class Person:
__metaclass__ = Countable
def __init__(self, name):
self.name = name
class Book:
__metaclass__ = Countable
def __init__(self, name, author):
self.name = name
self.author = author
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 33 / 57
37. Examples Counting
Counting Example (cont’d)
Testing
rah = Person("Robert Anson Heinlin")
b1 = Book("Stranger in a Strange Land", rah)
b2 = Book("Starship Troopers", rah)
print Person.count, Book.count
>>> 1 2
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 34 / 57
38. Examples Delegation
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
Meta-Classes in Python
4 Examples
Logging
Counting
Delegation
Associations
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 35 / 57
39. Examples Delegation
Automatic Delegation
Delegate
An object of class A that
dispatches all message of
class B to a target field of
type B.
Writing a delegate class is a monotonous work
But it can be done automatically
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 36 / 57
40. Examples Delegation
Delegation Using Meta-Classes
A delegation function decorator
def dlgt(cls, method):
def ret(self, *args):
method(self.__tgt__, *args)
return instancemethod(ret, None, cls)
instancemethod takes a function, an object/None and a class and
returns a method of the class
Auxiliary – Print class name
def clsname(self):
return self.__class__.__name__
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 37 / 57
41. Examples Delegation
Delegation Using Meta-Classes (cont’d)
The Delegate meta-class
class Delegate(type):
def __init__(cls, name, bases, dict):
type.__init__(cls, name, bases, dict)
tgtclass = cls.__tgtclass__
for name in dir(tgtclass):
val = getattr(tgtclass, name)
if callable(val):
setattr(cls, name, dlgt(cls, val))
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 38 / 57
42. Examples Delegation
Delegation Using Meta-Classes (cont’d)
The delegated class
class A:
def bar(self):
print clsname(self), ’bar’
def baz(self):
print clsname(self), ’baz’
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 39 / 57
43. Examples Delegation
Delegation Using Meta-Classes (cont’d)
The delegating class
class B:
metaclass = Delegate
tgtclass = A
def init (self, tgt):
self. tgt = tgt
def boo(self):
print clsname(self), ’boo’
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 40 / 57
44. Examples Delegation
Delegation Using Meta-Classes (cont’d)
Delegation test
>>> b = B(A())
>>> b.bar()
A bar
>>> b.baz()
A baz
>>> b.boo()
B boo
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 41 / 57
45. Examples Delegation
Simplified Syntax for with Meta-Classes with Args.
Thanks to Yoav Goldberg
Use a function to create the meta-class
def delegate_of(tgtclass):
class Delegate(type):
def __init__(cls, name, bases, dict):
type.__init__(cls, name, bases, dict)
for name in dir(tgtclass):
val = getattr(tgtclass, name)
if callable(val):
setattr(cls, name, dlgt(cls,val))
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 42 / 57
46. Examples Delegation
Simplified Syntax for Meta-Classes with Args.
Thanks to Yoav Goldberg
Use the function to generate a meta-class
class B:
metaclass = delegate_of(A)
def init (self, tgt):
self. tgt = tgt
def boo(self):
print clsname(self), ’boo’
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 43 / 57
47. Examples Associations
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
Meta-Classes in Python
4 Examples
Logging
Counting
Delegation
Associations
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 44 / 57
48. Examples Associations
Associations
0..m ab 0..n
A myA myB
B
Goals
Aggregation operations, like
a.getMyB().foreach().g()
r = b.getMyA().filter().f().map().h()
Optimizations: Multithreading, caching
No textual code generation
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 45 / 57
49. Examples Associations
Basic Aggregation
Replace all public methods with an aggregator wrapper
class Aggr(type):
def __init__(cls, name, bases, dct):
p = re.compile(’__.*__’)
type.__init__(cls, name, bases, {})
for key, item in dct.iteritems():
if callable(item) and not p.match(key):
m = instancemethod(cls.wrap(item), None, self)
setattr(self, key, m)
def wrap(cls, func):
def ret(self, *args):
return self.__aggr__(func, *args)
return ret
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 46 / 57
50. Examples Associations
Basic Aggregation (cont’d)
Make aggrs. that extend impl and wrap ifce
class ListAggr(Aggr):
@staticmethod
def make(name, impl, ifce):
dct = {}
for key in dir(ifce):
dct[key] = getattr(ifce, key)
return ListAggr(name, (impl,), dct)
def __init__(self, name, bases, dct):
Aggr.__init__(self, name, bases, dct)
base = bases[0]
ctr = base.__init__ % Use impl’s constructor
self.__init__ = instancemethod(ctr, None, self)
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 47 / 57
51. Examples Associations
List-Based Sequential Aggrs.
Store list in private field
class ListFunc(object):
def __init__(self, data):
self.__data__ = data
def onAdd(self, other): pass
def onRemove(self, other): pass
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 48 / 57
52. Examples Associations
List-Based Sequential Aggrs. (cont’d)
Sequential Foreach
class ListSeqForeach(ListFunc):
def __init__(self, data):
ListFunc.__init__(self, data)
def __aggr__(self, func, *args):
for inst in self.__data__:
func(inst, *args)
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 49 / 57
53. Examples Associations
List-Based Sequential Aggrs. (cont’d)
Sequential Map
class ListSeqMap(ListFunc):
def __init__(self, data):
ListFunc.__init__(self, data)
def __aggr__(self, func, *args):
ret = []
for inst in self.__data__:
ret.append(func(inst, *args))
return ret
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 50 / 57
54. Examples Associations
Binding It Together
Making an aggr. that extends seq. foreach
def makeForeachClass(cls):
return ListAggr.make(’...’, ListSeqForeach, cls)
ListFunc Aggr
ListSeqForeach ListAggr
cls ForeachClass
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 51 / 57
55. Examples Associations
Optimizations
Multithreaded Foreach
class ListSpawnForeach(ListFunc):
def __init__(self, data):
ListFunc.__init__(self, data)
def __aggr__(self, func, *args):
n = max(len(self.__data__)/K, 1)
ts = []
for c in chunks(self.__data__, n):
t = ForeachThread(c, func, args)
ts.append(t)
t.start()
for tr in ts: tr.join()
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 52 / 57
56. Examples Associations
Binding It Together, Multithreaded Version
Making an aggr. that extends parallel foreach
def makeForeachClass(cls):
return ListAggr.make(’...’, ListSpawnForeach, cls)
ListFunc Aggr
ListSpawnForeach ListAggr
cls ForeachClass
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 53 / 57
57. Examples Associations
Links
Download complete code
http://www.cs.bgu.ac.il/~gwiener/software/associations/
Read full paper
Proceedings of ENASE’2010 / By request
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 54 / 57
58. Summary
Outline
1 Introduction
2 OOP Hacking
3 Meta-Classes
4 Examples
5 Summary
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 55 / 57
59. Summary
Advantages of Meta-Classes
Turn this. . . Into this
P haarazu-Urh
os a
cr
-Y
eku Uru-Ne
tah
i Ia Dai-Uk
-W
ka
a-
Ha
kal -U
Tru-Saka
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 56 / 57
60. Summary
Thank You!
wiener.guy@gmail.com
Guy Wiener (WIS) Dynamic OOP and Meta-Classes in Python 24/5/2011 57 / 57