Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bff110f

Browse files
committed
Examples of metaprogramming in pure Python.
1 parent 558f66f commit bff110f

2 files changed

Lines changed: 291 additions & 0 deletions

File tree

Demo/metaclasses/Enum.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
"""Enumeration metaclass."""
2+
3+
import string
4+
5+
class EnumMetaClass:
6+
"""Metaclass for enumeration.
7+
8+
To define your own enumeration, do something like
9+
10+
class Color(Enum):
11+
red = 1
12+
green = 2
13+
blue = 3
14+
15+
Now, Color.red, Color.green and Color.blue behave totally
16+
different: they are enumerated values, not integers.
17+
18+
Enumerations cannot be instantiated; however they can be
19+
subclassed.
20+
21+
"""
22+
23+
def __init__(self, name, bases, dict):
24+
"""Constructor -- create an enumeration.
25+
26+
Called at the end of the class statement. The arguments are
27+
the name of the new class, a tuple containing the base
28+
classes, and a dictionary containing everything that was
29+
entered in the class' namespace during execution of the class
30+
statement. In the above example, it would be {'red': 1,
31+
'green': 2, 'blue': 3}.
32+
33+
"""
34+
for base in bases:
35+
if base.__class__ is not EnumMetaClass:
36+
raise TypeError, "Enumeration base class must be enumeration"
37+
bases = filter(lambda x: x is not Enum, bases)
38+
self.__name__ = name
39+
self.__bases__ = bases
40+
self.__dict = {}
41+
for key, value in dict.items():
42+
self.__dict[key] = EnumInstance(name, key, value)
43+
44+
def __getattr__(self, name):
45+
"""Return an enumeration value.
46+
47+
For example, Color.red returns the value corresponding to red.
48+
49+
XXX Perhaps the values should be created in the constructor?
50+
51+
This looks in the class dictionary and if it is not found
52+
there asks the base classes.
53+
54+
The special attribute __members__ returns the list of names
55+
defined in this class (it does not merge in the names defined
56+
in base classes).
57+
58+
"""
59+
if name == '__members__':
60+
return self.__dict.keys()
61+
62+
try:
63+
return self.__dict[name]
64+
except KeyError:
65+
for base in self.__bases__:
66+
try:
67+
return getattr(base, name)
68+
except AttributeError:
69+
continue
70+
71+
raise AttributeError, name
72+
73+
def __repr__(self):
74+
s = self.__name__
75+
if self.__bases__:
76+
s = s + '(' + string.join(map(lambda x: x.__name__,
77+
self.__bases__), ", ") + ')'
78+
if self.__dict:
79+
list = []
80+
for key, value in self.__dict.items():
81+
list.append("%s: %s" % (key, int(value)))
82+
s = "%s: {%s}" % (s, string.join(list, ", "))
83+
return s
84+
85+
86+
class EnumInstance:
87+
"""Class to represent an enumeration value.
88+
89+
EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
90+
like the integer 12 when compared, but doesn't support arithmetic.
91+
92+
XXX Should it record the actual enumeration rather than just its
93+
name?
94+
95+
"""
96+
97+
def __init__(self, classname, enumname, value):
98+
self.__classname = classname
99+
self.__enumname = enumname
100+
self.__value = value
101+
102+
def __int__(self):
103+
return self.__value
104+
105+
def __repr__(self):
106+
return "EnumInstance(%s, %s, %s)" % (`self.__classname`,
107+
`self.__enumname`,
108+
`self.__value`)
109+
110+
def __str__(self):
111+
return "%s.%s" % (self.__classname, self.__enumname)
112+
113+
def __cmp__(self, other):
114+
return cmp(self.__value, int(other))
115+
116+
117+
# Create the base class for enumerations.
118+
# It is an empty enumeration.
119+
Enum = EnumMetaClass("Enum", (), {})
120+
121+
122+
def _test():
123+
124+
class Color(Enum):
125+
red = 1
126+
green = 2
127+
blue = 3
128+
129+
print Color.red
130+
print dir(Color)
131+
132+
print Color.red == Color.red
133+
print Color.red == Color.blue
134+
print Color.red == 1
135+
print Color.red == 2
136+
137+
class ExtendedColor(Color):
138+
white = 0
139+
orange = 4
140+
yellow = 5
141+
purple = 6
142+
black = 7
143+
144+
print ExtendedColor.orange
145+
print ExtendedColor.red
146+
147+
print Color.red == ExtendedColor.red
148+
149+
class OtherColor(Enum):
150+
white = 4
151+
blue = 5
152+
153+
class MergedColor(Color, OtherColor):
154+
pass
155+
156+
print MergedColor.red
157+
print MergedColor.white
158+
159+
print Color
160+
print ExtendedColor
161+
print OtherColor
162+
print MergedColor
163+
164+
if __name__ == '__main__':
165+
_test()

Demo/metaclasses/Trace.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
"""Tracing metaclass."""
2+
3+
import types
4+
5+
class TraceMetaClass:
6+
"""Metaclass for tracing.
7+
8+
Classes defined using this metaclass have an automatic tracing
9+
feature -- by setting the __trace_output__ instance (or class)
10+
variable to a file object, trace messages about all calls are
11+
written to the file. The trace formatting can be changed by
12+
defining a suitable __trace_call__ method.
13+
14+
"""
15+
16+
__inited = 0
17+
18+
def __init__(self, name, bases, dict):
19+
self.__name__ = name
20+
self.__bases__ = bases
21+
self.__dict = dict
22+
# XXX Can't define __dict__, alas
23+
self.__inited = 1
24+
25+
def __getattr__(self, name):
26+
try:
27+
return self.__dict[name]
28+
except KeyError:
29+
for base in self.__bases__:
30+
try:
31+
return getattr(base, name)
32+
except AttributeError:
33+
pass
34+
raise AttributeError, name
35+
36+
def __setattr__(self, name, value):
37+
if not self.__inited:
38+
self.__dict__[name] = value
39+
else:
40+
self.__dict[name] = value
41+
42+
def __call__(self, *args, **kw):
43+
inst = TracingInstance()
44+
inst.__meta_init__(self)
45+
try:
46+
init = inst.__getattr__('__init__')
47+
except AttributeError:
48+
init = lambda: None
49+
apply(init, args, kw)
50+
return inst
51+
52+
__trace_output__ = None
53+
54+
class TracingInstance:
55+
"""Helper class to represent an instance of a tracing class."""
56+
57+
def __trace_call__(self, fp, fmt, *args):
58+
fp.write((fmt+'\n') % args)
59+
60+
def __meta_init__(self, klass):
61+
self.__class = klass
62+
63+
def __getattr__(self, name):
64+
# Invoked for any attr not in the instance's __dict__
65+
try:
66+
raw = self.__class.__getattr__(name)
67+
except AttributeError:
68+
raise AttributeError, name
69+
if type(raw) != types.FunctionType:
70+
return raw
71+
# It's a function
72+
fullname = self.__class.__name__ + "." + name
73+
if not self.__trace_output__ or name == '__trace_call__':
74+
return NotTracingWrapper(fullname, raw, self)
75+
else:
76+
return TracingWrapper(fullname, raw, self)
77+
78+
class NotTracingWrapper:
79+
def __init__(self, name, func, inst):
80+
self.__name__ = name
81+
self.func = func
82+
self.inst = inst
83+
def __call__(self, *args, **kw):
84+
return apply(self.func, (self.inst,) + args, kw)
85+
86+
class TracingWrapper(NotTracingWrapper):
87+
def __call__(self, *args, **kw):
88+
self.inst.__trace_call__(self.inst.__trace_output__,
89+
"calling %s, inst=%s, args=%s, kw=%s",
90+
self.__name__, self.inst, args, kw)
91+
try:
92+
rv = apply(self.func, (self.inst,) + args, kw)
93+
except:
94+
t, v, tb = sys.exc_info()
95+
self.inst.__trace_call__(self.inst.__trace_output__,
96+
"returning from %s with exception %s: %s",
97+
self.__name__, t, v)
98+
raise t, v, tb
99+
else:
100+
self.inst.__trace_call__(self.inst.__trace_output__,
101+
"returning from %s with value %s",
102+
self.__name__, rv)
103+
return rv
104+
105+
Traced = TraceMetaClass('Traced', (), {'__trace_output__': None})
106+
107+
108+
def _test():
109+
import sys
110+
class C(Traced):
111+
def __init__(self, x=0): self.x = x
112+
def m1(self, x): self.x = x
113+
def m2(self, y): return self.x + y
114+
C.__trace_output__ = sys.stdout
115+
x = C(4321)
116+
print x
117+
print x.x
118+
print x.m1(100)
119+
print x.m1(10)
120+
print x.m2(33)
121+
print x.m1(5)
122+
print x.m2(4000)
123+
print x.x
124+
125+
if __name__ == '__main__':
126+
_test()

0 commit comments

Comments
 (0)