1. Metaclass Programming in Python
Advanced OO concepts
Juan Manuel Gimeno Illa
jmgimeno@diei.udl.cat
December 2008
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 1 / 21
2. This is dangerous, so don’t do it at home :-)
[Metaclasses] are deeper magic than 99% of users should ever
worry about. If you wonder whether you need them, you don’t
(the people who actually need them know with certainty that
they need them, and don’t need an explanation about why).
Tim Peters (c.l.p post 2002-12-22)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 2 / 21
3. Outline
1 Basic Concepts
2 How classes are created
Inside class statement
Metaclass Programming
Metaclass Conflicts
3 More Examples
4 Concluding Remarks
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 3 / 21
4. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
5. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
6. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
7. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
8. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
9. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
10. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
11. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
12. Basic Concepts
Objects and Classes
Classes are templates used to create objects
that share structure (attributes) and behaviour (methods)
but have different state (attributes’ values)
For object obj, type(obj) is the class or type of obj
For object obj, type(type(obj)) is the metaclass or metatype of
obj
(Sometimes type(type(obj)) is referred as the metaclass of
type(obj) but this is incorrect)
The same way that classes shape objects, metaclasses shape classes.
For instance, in Python, the difference between new and old classes
resides in the metaclass used to create the classes
(Note that the difference in metaclass can affect the objects of the
classes. For instance, instances of new-style classes behave differently
than those of old-style ones)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 4 / 21
13. Basic Concepts
New and Old Classes
>>> class New(object): pass
...
>>> class Old: pass
... Differences in new and
>>> n = New() old style objects (for
>>> o = Old() instance, the mro of
>>> type(n) attributes) . . .
<class ’ main .New’>
>>> type(o) . . . are due to the
<type ’instance’> different metaclasses
>>> type(New) they have
<type ’type’>
>>> type(Old)
<type ’classobj’>
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 5 / 21
14. Basic Concepts
New and Old Classes
>>> class New(object): pass
...
>>> class Old: pass
... Differences in new and
>>> n = New() old style objects (for
>>> o = Old() instance, the mro of
>>> type(n) attributes) . . .
<class ’ main .New’>
>>> type(o) . . . are due to the
<type ’instance’> different metaclasses
>>> type(New) they have
<type ’type’>
>>> type(Old)
<type ’classobj’>
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 5 / 21
15. Basic Concepts
New and Old Classes
>>> class New(object): pass
...
>>> class Old: pass
... Differences in new and
>>> n = New() old style objects (for
>>> o = Old() instance, the mro of
>>> type(n) attributes) . . .
<class ’ main .New’>
>>> type(o) . . . are due to the
<type ’instance’> different metaclasses
>>> type(New) they have
<type ’type’>
>>> type(Old)
<type ’classobj’>
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 5 / 21
16. Basic Concepts
New and Old Classes
>>> class New(object): pass
...
>>> class Old: pass
... Differences in new and
>>> n = New() old style objects (for
>>> o = Old() instance, the mro of
>>> type(n) attributes) . . .
<class ’ main .New’>
>>> type(o) . . . are due to the
<type ’instance’> different metaclasses
>>> type(New) they have
<type ’type’>
>>> type(Old)
<type ’classobj’>
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 5 / 21
17. Basic Concepts
New and Old Classes
>>> class New(object): pass
...
>>> class Old: pass
... Differences in new and
>>> n = New() old style objects (for
>>> o = Old() instance, the mro of
>>> type(n) attributes) . . .
<class ’ main .New’>
>>> type(o) . . . are due to the
<type ’instance’> different metaclasses
>>> type(New) they have
<type ’type’>
>>> type(Old)
<type ’classobj’>
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 5 / 21
18. How classes are created Inside class statement
The built-in type
type(name, bases, attribs)(a.k.a types.TypeType) creates a
new-style class object
name is a string containing the name of the class
(C. name )
bases is a tuple containing the base classes for the new class
(C. bases )
attribs is a dictionary pairing the attribute’s names with
their corresponding values
So the usual class statement (when dealing with new-style classes)
class Class(base1, base2, ...):
statements
calls type with parameters ‘‘Class’’, (base1, base2, ...) and
a dictionary containing the bindings created by the execution of the
statements.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 6 / 21
19. How classes are created Inside class statement
The built-in type
type(name, bases, attribs)(a.k.a types.TypeType) creates a
new-style class object
name is a string containing the name of the class
(C. name )
bases is a tuple containing the base classes for the new class
(C. bases )
attribs is a dictionary pairing the attribute’s names with
their corresponding values
So the usual class statement (when dealing with new-style classes)
class Class(base1, base2, ...):
statements
calls type with parameters ‘‘Class’’, (base1, base2, ...) and
a dictionary containing the bindings created by the execution of the
statements.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 6 / 21
20. How classes are created Inside class statement
The built-in type
type(name, bases, attribs)(a.k.a types.TypeType) creates a
new-style class object
name is a string containing the name of the class
(C. name )
bases is a tuple containing the base classes for the new class
(C. bases )
attribs is a dictionary pairing the attribute’s names with
their corresponding values
So the usual class statement (when dealing with new-style classes)
class Class(base1, base2, ...):
statements
calls type with parameters ‘‘Class’’, (base1, base2, ...) and
a dictionary containing the bindings created by the execution of the
statements.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 6 / 21
21. How classes are created Inside class statement
The built-in type
type(name, bases, attribs)(a.k.a types.TypeType) creates a
new-style class object
name is a string containing the name of the class
(C. name )
bases is a tuple containing the base classes for the new class
(C. bases )
attribs is a dictionary pairing the attribute’s names with
their corresponding values
So the usual class statement (when dealing with new-style classes)
class Class(base1, base2, ...):
statements
calls type with parameters ‘‘Class’’, (base1, base2, ...) and
a dictionary containing the bindings created by the execution of the
statements.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 6 / 21
22. How classes are created Inside class statement
The built-in type
type(name, bases, attribs)(a.k.a types.TypeType) creates a
new-style class object
name is a string containing the name of the class
(C. name )
bases is a tuple containing the base classes for the new class
(C. bases )
attribs is a dictionary pairing the attribute’s names with
their corresponding values
So the usual class statement (when dealing with new-style classes)
class Class(base1, base2, ...):
statements
calls type with parameters ‘‘Class’’, (base1, base2, ...) and
a dictionary containing the bindings created by the execution of the
statements.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 6 / 21
23. How classes are created Inside class statement
Inside the class statement
When one defines a new-style class:
>>> class Class1(object):
... attrib = 1
... def __init__(self, n):
... self.n = n
One actually executes:
>>> class_name = quot;Class1quot;
>>> class_bases = (object,)
>>> class_dict = {}
>>> class_body = quot;quot;quot;
attrib = 1
def __init__(self, n):
self.n = n
quot;quot;quot;
>>> exec class_body in globals(), class_dict
>>> locals()[class_name] = type(class_name, class_bases, class_dict)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 7 / 21
24. How classes are created Inside class statement
Inside the class statement
When one defines a new-style class:
>>> class Class1(object):
... attrib = 1
... def __init__(self, n):
... self.n = n
One actually executes:
>>> class_name = quot;Class1quot;
>>> class_bases = (object,)
>>> class_dict = {}
>>> class_body = quot;quot;quot;
attrib = 1
def __init__(self, n):
self.n = n
quot;quot;quot;
>>> exec class_body in globals(), class_dict
>>> locals()[class_name] = type(class_name, class_bases, class_dict)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 7 / 21
25. How classes are created Inside class statement
Inside the class statement
When one defines a new-style class:
>>> class Class1(object):
... attrib = 1
... def __init__(self, n):
... self.n = n
One actually executes:
>>> class_name = quot;Class1quot;
>>> class_bases = (object,)
>>> class_dict = {}
>>> class_body = quot;quot;quot;
attrib = 1
def __init__(self, n):
self.n = n
quot;quot;quot;
>>> exec class_body in globals(), class_dict
>>> locals()[class_name] = type(class_name, class_bases, class_dict)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 7 / 21
26. How classes are created Inside class statement
Inside the class statement
When one defines a new-style class:
>>> class Class1(object):
... attrib = 1
... def __init__(self, n):
... self.n = n
One actually executes:
>>> class_name = quot;Class1quot;
>>> class_bases = (object,)
>>> class_dict = {}
>>> class_body = quot;quot;quot;
attrib = 1
def __init__(self, n):
self.n = n
quot;quot;quot;
>>> exec class_body in globals(), class_dict
>>> locals()[class_name] = type(class_name, class_bases, class_dict)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 7 / 21
27. How classes are created Inside class statement
The full truth of the class statement
To execute a class statement:
1 Python first collects the class name in a string n, the base classes into
a tuple t and executes the body in dictionary d
2 Then determines the metaclass to use for the new class object C
1 When metaclass is a key in d, then M = d[’ metaclass ’]
2 When t is nonempty, then M is the leafmost1 metaclass among all the
metaclasses of C’s bases that are not old-style classes
3 If the current module has a global variable metaclass , then M is
the value of this variable
4 Failing all of these, M defaults to types.ClassType, that is, an
old-style class is created
3 Finally, C = M(n, t, d)
1
If the metaclasses of C’s bases’ do not form an inheritance lattice including its lower
bound - i.e. if there is no leafmost metaclass - Python raises and exception diagnosing
this metatype conflict.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 8 / 21
28. How classes are created Inside class statement
The full truth of the class statement
To execute a class statement:
1 Python first collects the class name in a string n, the base classes into
a tuple t and executes the body in dictionary d
2 Then determines the metaclass to use for the new class object C
1 When metaclass is a key in d, then M = d[’ metaclass ’]
2 When t is nonempty, then M is the leafmost1 metaclass among all the
metaclasses of C’s bases that are not old-style classes
3 If the current module has a global variable metaclass , then M is
the value of this variable
4 Failing all of these, M defaults to types.ClassType, that is, an
old-style class is created
3 Finally, C = M(n, t, d)
1
If the metaclasses of C’s bases’ do not form an inheritance lattice including its lower
bound - i.e. if there is no leafmost metaclass - Python raises and exception diagnosing
this metatype conflict.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 8 / 21
29. How classes are created Inside class statement
The full truth of the class statement
To execute a class statement:
1 Python first collects the class name in a string n, the base classes into
a tuple t and executes the body in dictionary d
2 Then determines the metaclass to use for the new class object C
1 When metaclass is a key in d, then M = d[’ metaclass ’]
2 When t is nonempty, then M is the leafmost1 metaclass among all the
metaclasses of C’s bases that are not old-style classes
3 If the current module has a global variable metaclass , then M is
the value of this variable
4 Failing all of these, M defaults to types.ClassType, that is, an
old-style class is created
3 Finally, C = M(n, t, d)
1
If the metaclasses of C’s bases’ do not form an inheritance lattice including its lower
bound - i.e. if there is no leafmost metaclass - Python raises and exception diagnosing
this metatype conflict.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 8 / 21
30. How classes are created Inside class statement
The full truth of the class statement
To execute a class statement:
1 Python first collects the class name in a string n, the base classes into
a tuple t and executes the body in dictionary d
2 Then determines the metaclass to use for the new class object C
1 When metaclass is a key in d, then M = d[’ metaclass ’]
2 When t is nonempty, then M is the leafmost1 metaclass among all the
metaclasses of C’s bases that are not old-style classes
3 If the current module has a global variable metaclass , then M is
the value of this variable
4 Failing all of these, M defaults to types.ClassType, that is, an
old-style class is created
3 Finally, C = M(n, t, d)
1
If the metaclasses of C’s bases’ do not form an inheritance lattice including its lower
bound - i.e. if there is no leafmost metaclass - Python raises and exception diagnosing
this metatype conflict.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 8 / 21
31. How classes are created Inside class statement
The full truth of the class statement
To execute a class statement:
1 Python first collects the class name in a string n, the base classes into
a tuple t and executes the body in dictionary d
2 Then determines the metaclass to use for the new class object C
1 When metaclass is a key in d, then M = d[’ metaclass ’]
2 When t is nonempty, then M is the leafmost1 metaclass among all the
metaclasses of C’s bases that are not old-style classes
3 If the current module has a global variable metaclass , then M is
the value of this variable
4 Failing all of these, M defaults to types.ClassType, that is, an
old-style class is created
3 Finally, C = M(n, t, d)
1
If the metaclasses of C’s bases’ do not form an inheritance lattice including its lower
bound - i.e. if there is no leafmost metaclass - Python raises and exception diagnosing
this metatype conflict.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 8 / 21
32. How classes are created Inside class statement
The full truth of the class statement
To execute a class statement:
1 Python first collects the class name in a string n, the base classes into
a tuple t and executes the body in dictionary d
2 Then determines the metaclass to use for the new class object C
1 When metaclass is a key in d, then M = d[’ metaclass ’]
2 When t is nonempty, then M is the leafmost1 metaclass among all the
metaclasses of C’s bases that are not old-style classes
3 If the current module has a global variable metaclass , then M is
the value of this variable
4 Failing all of these, M defaults to types.ClassType, that is, an
old-style class is created
3 Finally, C = M(n, t, d)
1
If the metaclasses of C’s bases’ do not form an inheritance lattice including its lower
bound - i.e. if there is no leafmost metaclass - Python raises and exception diagnosing
this metatype conflict.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 8 / 21
33. How classes are created Inside class statement
The full truth of the class statement
To execute a class statement:
1 Python first collects the class name in a string n, the base classes into
a tuple t and executes the body in dictionary d
2 Then determines the metaclass to use for the new class object C
1 When metaclass is a key in d, then M = d[’ metaclass ’]
2 When t is nonempty, then M is the leafmost1 metaclass among all the
metaclasses of C’s bases that are not old-style classes
3 If the current module has a global variable metaclass , then M is
the value of this variable
4 Failing all of these, M defaults to types.ClassType, that is, an
old-style class is created
3 Finally, C = M(n, t, d)
1
If the metaclasses of C’s bases’ do not form an inheritance lattice including its lower
bound - i.e. if there is no leafmost metaclass - Python raises and exception diagnosing
this metatype conflict.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 8 / 21
34. How classes are created Inside class statement
The full truth of the class statement
To execute a class statement:
1 Python first collects the class name in a string n, the base classes into
a tuple t and executes the body in dictionary d
2 Then determines the metaclass to use for the new class object C
1 When metaclass is a key in d, then M = d[’ metaclass ’]
2 When t is nonempty, then M is the leafmost1 metaclass among all the
metaclasses of C’s bases that are not old-style classes
3 If the current module has a global variable metaclass , then M is
the value of this variable
4 Failing all of these, M defaults to types.ClassType, that is, an
old-style class is created
3 Finally, C = M(n, t, d)
1
If the metaclasses of C’s bases’ do not form an inheritance lattice including its lower
bound - i.e. if there is no leafmost metaclass - Python raises and exception diagnosing
this metatype conflict.
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 8 / 21
35. How classes are created Metaclass Programming
A very simple metaclass
Redefining method repr in class changes the way python show its
instances
So to change the way python shows a class, we redefine repr in the
metaclass
>>> class MetaPretty(type):
... def __repr__(cls):
... return quot;I’m the class %squot; % cls.__name__
...
>>> class Ugly: pass
>>> Ugly
<class ’__main__.Ugly’>
>>> class Pretty(object):
... __metaclass__ = MetaPretty
>>> Pretty
I’m the class Pretty
Metaclass programming is easier than you thought !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 9 / 21
36. How classes are created Metaclass Programming
A very simple metaclass
Redefining method repr in class changes the way python show its
instances
So to change the way python shows a class, we redefine repr in the
metaclass
>>> class MetaPretty(type):
... def __repr__(cls):
... return quot;I’m the class %squot; % cls.__name__
...
>>> class Ugly: pass
>>> Ugly
<class ’__main__.Ugly’>
>>> class Pretty(object):
... __metaclass__ = MetaPretty
>>> Pretty
I’m the class Pretty
Metaclass programming is easier than you thought !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 9 / 21
37. How classes are created Metaclass Programming
A very simple metaclass
Redefining method repr in class changes the way python show its
instances
So to change the way python shows a class, we redefine repr in the
metaclass
>>> class MetaPretty(type):
... def __repr__(cls):
... return quot;I’m the class %squot; % cls.__name__
...
>>> class Ugly: pass
>>> Ugly
<class ’__main__.Ugly’>
>>> class Pretty(object):
... __metaclass__ = MetaPretty
>>> Pretty
I’m the class Pretty
Metaclass programming is easier than you thought !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 9 / 21
38. How classes are created Metaclass Programming
A very simple metaclass
Redefining method repr in class changes the way python show its
instances
So to change the way python shows a class, we redefine repr in the
metaclass
>>> class MetaPretty(type):
... def __repr__(cls):
... return quot;I’m the class %squot; % cls.__name__
...
>>> class Ugly: pass
>>> Ugly
<class ’__main__.Ugly’>
>>> class Pretty(object):
... __metaclass__ = MetaPretty
>>> Pretty
I’m the class Pretty
Metaclass programming is easier than you thought !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 9 / 21
39. How classes are created Metaclass Programming
Automatic property creation I
We don’t want to tell python the properties defined in a class if there are
methods in the class that evidently want a property defined !!!
We implement it redefining init
class MetaAutoProp(type):
def __init__(cls, name, bases, dict):
super(MetaAutoProp, cls).__init__(name, bases, dict)
props = set(name[5:] for name in dict.iterkeys()
if name.startswith(quot;_get_quot;) or
name.startswith(quot;_set_quot;))
for name in props:
fget = getattr(cls, quot;_get_%squot; % name, None)
fset = getattr(cls, quot;_set_%squot; % name, None)
setattr(cls, name, property(fget, fset))
class AutoProp(object): __metaclass__ = MetaAutoProp
class UseX(AutoProp):
def __init__(self): self.__x = 0
def _get_x(self): return self.__x
def _set_x(self, x): self.__x = x
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 10 / 21
40. How classes are created Metaclass Programming
Automatic property creation I
We don’t want to tell python the properties defined in a class if there are
methods in the class that evidently want a property defined !!!
We implement it redefining init
class MetaAutoProp(type):
def __init__(cls, name, bases, dict):
super(MetaAutoProp, cls).__init__(name, bases, dict)
props = set(name[5:] for name in dict.iterkeys()
if name.startswith(quot;_get_quot;) or
name.startswith(quot;_set_quot;))
for name in props:
fget = getattr(cls, quot;_get_%squot; % name, None)
fset = getattr(cls, quot;_set_%squot; % name, None)
setattr(cls, name, property(fget, fset))
class AutoProp(object): __metaclass__ = MetaAutoProp
class UseX(AutoProp):
def __init__(self): self.__x = 0
def _get_x(self): return self.__x
def _set_x(self, x): self.__x = x
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 10 / 21
41. How classes are created Metaclass Programming
Automatic property creation I
We don’t want to tell python the properties defined in a class if there are
methods in the class that evidently want a property defined !!!
We implement it redefining init
class MetaAutoProp(type):
def __init__(cls, name, bases, dict):
super(MetaAutoProp, cls).__init__(name, bases, dict)
props = set(name[5:] for name in dict.iterkeys()
if name.startswith(quot;_get_quot;) or
name.startswith(quot;_set_quot;))
for name in props:
fget = getattr(cls, quot;_get_%squot; % name, None)
fset = getattr(cls, quot;_set_%squot; % name, None)
setattr(cls, name, property(fget, fset))
class AutoProp(object): __metaclass__ = MetaAutoProp
class UseX(AutoProp):
def __init__(self): self.__x = 0
def _get_x(self): return self.__x
def _set_x(self, x): self.__x = x
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 10 / 21
42. How classes are created Metaclass Programming
Automatic property creation II
The same as before but this time the implementation redefines new
class MetaAutoProp(type):
def __new__(mcl, classname, bases, dict):
props = set(name[5:] for name in dict.iterkeys()
if name.startswith(quot;_get_quot;) or
name.startswith(quot;_set_quot;))
for name in props:
fget = dict.get(quot;_get_%squot; % name)
fset = dict.get(quot;_set_%squot; % name)
dict[name] = property(fget, fset)
super_ = super(MetaAutoProp, mcl)
return super_.__new__(mcl, classname, bases, dict)
class AutoProp(object): __metaclass__ = MetaAutoProp
class UseX(AutoProp):
def __init__(self): self.__x = 0
def _get_x(self): return self.__x
def _set_x(self, x): self.__x = x
Deciding which way to go is not clearly defined
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 11 / 21
43. How classes are created Metaclass Programming
Automatic property creation II
The same as before but this time the implementation redefines new
class MetaAutoProp(type):
def __new__(mcl, classname, bases, dict):
props = set(name[5:] for name in dict.iterkeys()
if name.startswith(quot;_get_quot;) or
name.startswith(quot;_set_quot;))
for name in props:
fget = dict.get(quot;_get_%squot; % name)
fset = dict.get(quot;_set_%squot; % name)
dict[name] = property(fget, fset)
super_ = super(MetaAutoProp, mcl)
return super_.__new__(mcl, classname, bases, dict)
class AutoProp(object): __metaclass__ = MetaAutoProp
class UseX(AutoProp):
def __init__(self): self.__x = 0
def _get_x(self): return self.__x
def _set_x(self, x): self.__x = x
Deciding which way to go is not clearly defined
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 11 / 21
44. How classes are created Metaclass Programming
Automatic property creation II
The same as before but this time the implementation redefines new
class MetaAutoProp(type):
def __new__(mcl, classname, bases, dict):
props = set(name[5:] for name in dict.iterkeys()
if name.startswith(quot;_get_quot;) or
name.startswith(quot;_set_quot;))
for name in props:
fget = dict.get(quot;_get_%squot; % name)
fset = dict.get(quot;_set_%squot; % name)
dict[name] = property(fget, fset)
super_ = super(MetaAutoProp, mcl)
return super_.__new__(mcl, classname, bases, dict)
class AutoProp(object): __metaclass__ = MetaAutoProp
class UseX(AutoProp):
def __init__(self): self.__x = 0
def _get_x(self): return self.__x
def _set_x(self, x): self.__x = x
Deciding which way to go is not clearly defined
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 11 / 21
45. How classes are created Metaclass Programming
Automatic Initialization of Instance Attributes
import inspect
class auto_attr(object):
def __init__(self, factory, *args, **kwargs):
self.creation_data = (factory, args, kwargs)
def is_auto_attr(attr):
return isinstance(attr, auto_attr)
class MetaAutoAttr(type):
def __call__(cls, *args, **kwargs):
obj = super(MetaAutoAttr, cls).__call__(*args, **kwargs)
for attr, value in inspect.getmembers(cls, is_auto_attr):
factory, a, k = value.creation_data
setattr(obj, attr, factory(*a, **k))
return obj
class AutoAttr(object): __metaclass__ = MetaAutoAttr
class Recorder(AutoAttr):
count = 0 # is immutable so no shared among instances
events = auto_attr(list)
def record(self, event):
self.count += 1
self.events.append((self.count, event))
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 12 / 21
46. How classes are created Metaclass Conflicts
But, sometimes, conflicts happen
Imagine one wants a class with both behaviours. If one tries:
from autoprop import AutoProp
from autoattr import AutoAttr, auto_attr
class Both(AutoProp, AutoAttr):
__x = auto_attr(list)
def _get_x(self): return self.__x
def _set_x(self, v): self.__x = v
One gets:
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict)
subclass of the metaclasses of all its bases
The problem is that python needs to find a metaclass that brings both
behaviours at the same time
(This is the application of the Liskov Substitution Principle applied to
metaclasses)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 13 / 21
47. How classes are created Metaclass Conflicts
But, sometimes, conflicts happen
Imagine one wants a class with both behaviours. If one tries:
from autoprop import AutoProp
from autoattr import AutoAttr, auto_attr
class Both(AutoProp, AutoAttr):
__x = auto_attr(list)
def _get_x(self): return self.__x
def _set_x(self, v): self.__x = v
One gets:
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict)
subclass of the metaclasses of all its bases
The problem is that python needs to find a metaclass that brings both
behaviours at the same time
(This is the application of the Liskov Substitution Principle applied to
metaclasses)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 13 / 21
48. How classes are created Metaclass Conflicts
But, sometimes, conflicts happen
Imagine one wants a class with both behaviours. If one tries:
from autoprop import AutoProp
from autoattr import AutoAttr, auto_attr
class Both(AutoProp, AutoAttr):
__x = auto_attr(list)
def _get_x(self): return self.__x
def _set_x(self, v): self.__x = v
One gets:
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict)
subclass of the metaclasses of all its bases
The problem is that python needs to find a metaclass that brings both
behaviours at the same time
(This is the application of the Liskov Substitution Principle applied to
metaclasses)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 13 / 21
49. How classes are created Metaclass Conflicts
But, sometimes, conflicts happen
Imagine one wants a class with both behaviours. If one tries:
from autoprop import AutoProp
from autoattr import AutoAttr, auto_attr
class Both(AutoProp, AutoAttr):
__x = auto_attr(list)
def _get_x(self): return self.__x
def _set_x(self, v): self.__x = v
One gets:
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict)
subclass of the metaclasses of all its bases
The problem is that python needs to find a metaclass that brings both
behaviours at the same time
(This is the application of the Liskov Substitution Principle applied to
metaclasses)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 13 / 21
50. How classes are created Metaclass Conflicts
But, sometimes, conflicts happen
Imagine one wants a class with both behaviours. If one tries:
from autoprop import AutoProp
from autoattr import AutoAttr, auto_attr
class Both(AutoProp, AutoAttr):
__x = auto_attr(list)
def _get_x(self): return self.__x
def _set_x(self, v): self.__x = v
One gets:
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict)
subclass of the metaclasses of all its bases
The problem is that python needs to find a metaclass that brings both
behaviours at the same time
(This is the application of the Liskov Substitution Principle applied to
metaclasses)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 13 / 21
51. How classes are created Metaclass Conflicts
But, sometimes, conflicts happen
Imagine one wants a class with both behaviours. If one tries:
from autoprop import AutoProp
from autoattr import AutoAttr, auto_attr
class Both(AutoProp, AutoAttr):
__x = auto_attr(list)
def _get_x(self): return self.__x
def _set_x(self, v): self.__x = v
One gets:
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict)
subclass of the metaclasses of all its bases
The problem is that python needs to find a metaclass that brings both
behaviours at the same time
(This is the application of the Liskov Substitution Principle applied to
metaclasses)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 13 / 21
52. How classes are created Metaclass Conflicts
Solving the metaclass conflict
To ensured it, the metaclass to use must be a subclass of all those of the
bases of the class
(Technically it must be minimal in the inheritance subgraph of the metaclasses
of the bases considered as a lattice)
Some languages create an on-the-fly this minimal metaclass if needed
Python needs you to solve the problem , so:
from autoprop import MetaAutoProp
from autoattr import MetaAutoAttr, auto_attr
class MetaBoth(MetaAutoAttr, MetaAutoProp): pass
class Both(object):
__metaclass__ = MetaBoth
__x = auto_attr(list)
def _get_x(self):
return self.__x
def _set_x(self, value):
self.__x = value
(A recipe exists in the Python Cookbook that solves this problem by defining
a metaclass factory method which creates the appropriate metaclass when
needed)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 14 / 21
53. How classes are created Metaclass Conflicts
Solving the metaclass conflict
To ensured it, the metaclass to use must be a subclass of all those of the
bases of the class
(Technically it must be minimal in the inheritance subgraph of the metaclasses
of the bases considered as a lattice)
Some languages create an on-the-fly this minimal metaclass if needed
Python needs you to solve the problem , so:
from autoprop import MetaAutoProp
from autoattr import MetaAutoAttr, auto_attr
class MetaBoth(MetaAutoAttr, MetaAutoProp): pass
class Both(object):
__metaclass__ = MetaBoth
__x = auto_attr(list)
def _get_x(self):
return self.__x
def _set_x(self, value):
self.__x = value
(A recipe exists in the Python Cookbook that solves this problem by defining
a metaclass factory method which creates the appropriate metaclass when
needed)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 14 / 21
54. How classes are created Metaclass Conflicts
Solving the metaclass conflict
To ensured it, the metaclass to use must be a subclass of all those of the
bases of the class
(Technically it must be minimal in the inheritance subgraph of the metaclasses
of the bases considered as a lattice)
Some languages create an on-the-fly this minimal metaclass if needed
Python needs you to solve the problem , so:
from autoprop import MetaAutoProp
from autoattr import MetaAutoAttr, auto_attr
class MetaBoth(MetaAutoAttr, MetaAutoProp): pass
class Both(object):
__metaclass__ = MetaBoth
__x = auto_attr(list)
def _get_x(self):
return self.__x
def _set_x(self, value):
self.__x = value
(A recipe exists in the Python Cookbook that solves this problem by defining
a metaclass factory method which creates the appropriate metaclass when
needed)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 14 / 21
55. How classes are created Metaclass Conflicts
Solving the metaclass conflict
To ensured it, the metaclass to use must be a subclass of all those of the
bases of the class
(Technically it must be minimal in the inheritance subgraph of the metaclasses
of the bases considered as a lattice)
Some languages create an on-the-fly this minimal metaclass if needed
Python needs you to solve the problem , so:
from autoprop import MetaAutoProp
from autoattr import MetaAutoAttr, auto_attr
class MetaBoth(MetaAutoAttr, MetaAutoProp): pass
class Both(object):
__metaclass__ = MetaBoth
__x = auto_attr(list)
def _get_x(self):
return self.__x
def _set_x(self, value):
self.__x = value
(A recipe exists in the Python Cookbook that solves this problem by defining
a metaclass factory method which creates the appropriate metaclass when
needed)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 14 / 21
56. How classes are created Metaclass Conflicts
Solving the metaclass conflict
To ensured it, the metaclass to use must be a subclass of all those of the
bases of the class
(Technically it must be minimal in the inheritance subgraph of the metaclasses
of the bases considered as a lattice)
Some languages create an on-the-fly this minimal metaclass if needed
Python needs you to solve the problem , so:
from autoprop import MetaAutoProp
from autoattr import MetaAutoAttr, auto_attr
class MetaBoth(MetaAutoAttr, MetaAutoProp): pass
class Both(object):
__metaclass__ = MetaBoth
__x = auto_attr(list)
def _get_x(self):
return self.__x
def _set_x(self, value):
self.__x = value
(A recipe exists in the Python Cookbook that solves this problem by defining
a metaclass factory method which creates the appropriate metaclass when
needed)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 14 / 21
57. How classes are created Metaclass Conflicts
Solving the metaclass conflict
To ensured it, the metaclass to use must be a subclass of all those of the
bases of the class
(Technically it must be minimal in the inheritance subgraph of the metaclasses
of the bases considered as a lattice)
Some languages create an on-the-fly this minimal metaclass if needed
Python needs you to solve the problem , so:
from autoprop import MetaAutoProp
from autoattr import MetaAutoAttr, auto_attr
class MetaBoth(MetaAutoAttr, MetaAutoProp): pass
class Both(object):
__metaclass__ = MetaBoth
__x = auto_attr(list)
def _get_x(self):
return self.__x
def _set_x(self, value):
self.__x = value
(A recipe exists in the Python Cookbook that solves this problem by defining
a metaclass factory method which creates the appropriate metaclass when
needed)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 14 / 21
58. More Examples
Avoiding multiple initialization of Singletons
The Singleton class that was presented before needed init to be
idempotent. Changing its metaclass solves it:
# Singleton classes are only init’ed once
class Singleton(object):
class __metaclass__(type):
_initialized = set()
def __call__(cls, *args, **kwargs):
inits = Singleton.__metaclass__._initialized
obj = cls.__new__(cls, *args, **kwargs)
if isinstance(obj, cls) and
cls not in inits:
inits.add(cls)
obj.__init__(*args, **kwargs)
return obj
_singletons = {}
def __new__(cls, *args, **kwds):
if cls not in cls._singletons:
s = super(Singleton, cls)
cls._singletons[cls] =
super(Singleton, cls).__new__(cls, *args, **kwds)
return cls._singletons[cls]
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 15 / 21
59. More Examples
Avoiding multiple initialization of Singletons
The Singleton class that was presented before needed init to be
idempotent. Changing its metaclass solves it:
# Singleton classes are only init’ed once
class Singleton(object):
class __metaclass__(type):
_initialized = set()
def __call__(cls, *args, **kwargs):
inits = Singleton.__metaclass__._initialized
obj = cls.__new__(cls, *args, **kwargs)
if isinstance(obj, cls) and
cls not in inits:
inits.add(cls)
obj.__init__(*args, **kwargs)
return obj
_singletons = {}
def __new__(cls, *args, **kwds):
if cls not in cls._singletons:
s = super(Singleton, cls)
cls._singletons[cls] =
super(Singleton, cls).__new__(cls, *args, **kwds)
return cls._singletons[cls]
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 15 / 21
60. More Examples
Enforcing naming rules
We don’t want classes with attributes that are not lowercase to be ever
created !!!!
class InvalidAttribName(TypeError): pass
class MetaEnsureAttribNames(type):
def __new__(mcl, name, bases, attrs):
invalids = [attr for attr in attrs
if not attr.islower()]
if invalids:
msg = quot;Invalid Attributes: quot; + quot;, quot;.join(invalids)
raise InvalidAttribName, msg
super_ = super(MetaEnsureAttribNames, mcl)
return super_.__new__(mcl, name, bases, attrs)
class EnsureAttribNames(object):
__metaclass__ = MetaEnsureAttribNames
(You can experiment with different rules for methods, rules for class names,
etc.)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 16 / 21
61. More Examples
Enforcing naming rules
We don’t want classes with attributes that are not lowercase to be ever
created !!!!
class InvalidAttribName(TypeError): pass
class MetaEnsureAttribNames(type):
def __new__(mcl, name, bases, attrs):
invalids = [attr for attr in attrs
if not attr.islower()]
if invalids:
msg = quot;Invalid Attributes: quot; + quot;, quot;.join(invalids)
raise InvalidAttribName, msg
super_ = super(MetaEnsureAttribNames, mcl)
return super_.__new__(mcl, name, bases, attrs)
class EnsureAttribNames(object):
__metaclass__ = MetaEnsureAttribNames
(You can experiment with different rules for methods, rules for class names,
etc.)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 16 / 21
62. More Examples
Enforcing naming rules
We don’t want classes with attributes that are not lowercase to be ever
created !!!!
class InvalidAttribName(TypeError): pass
class MetaEnsureAttribNames(type):
def __new__(mcl, name, bases, attrs):
invalids = [attr for attr in attrs
if not attr.islower()]
if invalids:
msg = quot;Invalid Attributes: quot; + quot;, quot;.join(invalids)
raise InvalidAttribName, msg
super_ = super(MetaEnsureAttribNames, mcl)
return super_.__new__(mcl, name, bases, attrs)
class EnsureAttribNames(object):
__metaclass__ = MetaEnsureAttribNames
(You can experiment with different rules for methods, rules for class names,
etc.)
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 16 / 21
63. More Examples
Checking Whether Interfaces are Implemented
We want to extend python capabilities to respresent the idea of an interface
and to ensure that a class that declares implementing one, actually does it
Interfaces are represented by simple classes
class IConnectable(object):
def send(self, msg): pass
def receive(self): pass
Declaring an interface is done with a class’ attribute and is ensured by a
metaclass
class Channel(object):
__metaclass__ = MetaInterfaceChecker
__implements__ = IConnectable
def send(self, msg): ....
def receive(self): ....
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 17 / 21
64. More Examples
Checking Whether Interfaces are Implemented
We want to extend python capabilities to respresent the idea of an interface
and to ensure that a class that declares implementing one, actually does it
Interfaces are represented by simple classes
class IConnectable(object):
def send(self, msg): pass
def receive(self): pass
Declaring an interface is done with a class’ attribute and is ensured by a
metaclass
class Channel(object):
__metaclass__ = MetaInterfaceChecker
__implements__ = IConnectable
def send(self, msg): ....
def receive(self): ....
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 17 / 21
65. More Examples
Checking Whether Interfaces are Implemented
We want to extend python capabilities to respresent the idea of an interface
and to ensure that a class that declares implementing one, actually does it
Interfaces are represented by simple classes
class IConnectable(object):
def send(self, msg): pass
def receive(self): pass
Declaring an interface is done with a class’ attribute and is ensured by a
metaclass
class Channel(object):
__metaclass__ = MetaInterfaceChecker
__implements__ = IConnectable
def send(self, msg): ....
def receive(self): ....
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 17 / 21
66. More Examples
Checking Whether Interfaces are Implemented
We want to extend python capabilities to respresent the idea of an interface
and to ensure that a class that declares implementing one, actually does it
Interfaces are represented by simple classes
class IConnectable(object):
def send(self, msg): pass
def receive(self): pass
Declaring an interface is done with a class’ attribute and is ensured by a
metaclass
class Channel(object):
__metaclass__ = MetaInterfaceChecker
__implements__ = IConnectable
def send(self, msg): ....
def receive(self): ....
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 17 / 21
67. More Examples
Checking Whether Interfaces are Implemented
We want to extend python capabilities to respresent the idea of an interface
and to ensure that a class that declares implementing one, actually does it
Interfaces are represented by simple classes
class IConnectable(object):
def send(self, msg): pass
def receive(self): pass
Declaring an interface is done with a class’ attribute and is ensured by a
metaclass
class Channel(object):
__metaclass__ = MetaInterfaceChecker
__implements__ = IConnectable
def send(self, msg): ....
def receive(self): ....
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 17 / 21
68. More Examples
Checking Whether Interfaces are Implemented
The following metaclass checks if all the methods in all declared interfaces are
defined in the class
(The implementation is na¨ so you can enhance it. hint: use module
ıve,
inspect)
import set
class InterfaceOmission(TypeError): pass
class MetaInterfaceChecker(type):
def __init__(cls, classname, bases, classdict):
super(MetaInterfaceChecker, cls).__init__(classname,
bases,
classdict)
cls_defines = set(dir(cls))
for interface in cls.__implements__:
itf_requires = set(dir(interface))
if not itf_requires.issubset(cls_defines):
raise (InterfaceOmission,
list(itf_requires - cls_defines))
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 18 / 21
69. More Examples
Checking Whether Interfaces are Implemented
The following metaclass checks if all the methods in all declared interfaces are
defined in the class
(The implementation is na¨ so you can enhance it. hint: use module
ıve,
inspect)
import set
class InterfaceOmission(TypeError): pass
class MetaInterfaceChecker(type):
def __init__(cls, classname, bases, classdict):
super(MetaInterfaceChecker, cls).__init__(classname,
bases,
classdict)
cls_defines = set(dir(cls))
for interface in cls.__implements__:
itf_requires = set(dir(interface))
if not itf_requires.issubset(cls_defines):
raise (InterfaceOmission,
list(itf_requires - cls_defines))
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 18 / 21
70. More Examples
Checking Whether Interfaces are Implemented
The following metaclass checks if all the methods in all declared interfaces are
defined in the class
(The implementation is na¨ so you can enhance it. hint: use module
ıve,
inspect)
import set
class InterfaceOmission(TypeError): pass
class MetaInterfaceChecker(type):
def __init__(cls, classname, bases, classdict):
super(MetaInterfaceChecker, cls).__init__(classname,
bases,
classdict)
cls_defines = set(dir(cls))
for interface in cls.__implements__:
itf_requires = set(dir(interface))
if not itf_requires.issubset(cls_defines):
raise (InterfaceOmission,
list(itf_requires - cls_defines))
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 18 / 21
71. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
72. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
73. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
74. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
75. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
76. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
77. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
78. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
79. Concluding Remarks
Conclusions
Metaclasses must not be abused
they put you dangerously near to the dark side
if there’s a simple way to perform the same, don’t use them
but sometimes they simplify things
or lead to more efficient solutions
But understanding them
shows you the whole picture of python’s OO
gives you new ways to think about solutions
And they are fun !!!
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 19 / 21
80. Bibliography
Bibliography
Shalahb Chaturvedi, Python Types and Objects
Mike Fletcher, Metaclasses, Who, Why, When, Python Conference
(Pycon) 2004.
Ira R. Forman and Scott Danforth, Putting Metaclasses to Work.
Addison-Wesley, 1999.
Alex Martelli, Python in a Nutshell (2nd Edition), O’Reilly Media Inc,
2006.
Alex Martelli, Python Metaclasses
Alex Martelli, Anna Martelli, Python Cookbook (2nd Edition),
O’Reilly Media Inc, 2005.
The recipes are based on those in ActiveState Python Cookbook.
David Mertz, A Primer on Python Metaclass Programming
Guido Van Rossum, Unifying types and classes in Python 2.2
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 20 / 21
81. License
License
Aquesta obra est` subjecta a una llic`ncia Reconeixement-Compartir amb
a e
la mateixa llic`ncia 2.5 Espanya de Creative Commons.
e
Per veure’n una c`pia, visiteu
o
http://creativecommons.org/licenses/by-sa/2.5/es/
o envieu una carta a
Creative Commons
559 Nathan Abbott Way
Stanford
California 94305
USA
J.M.Gimeno (jmgimeno@diei.udl.cat) Metaclasses December 2008 21 / 21