-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmetaprogram.py
More file actions
207 lines (164 loc) · 7.02 KB
/
Copy pathmetaprogram.py
File metadata and controls
207 lines (164 loc) · 7.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
"""
metaprogram.py — Python Metaprogramming Demonstration
Dynamically generates a class with methods based on a configuration dictionary.
Methods are constructed at runtime using compile/exec — the class and its methods
do not exist in the source code; they are synthesized from data.
This demonstrates Python's deep runtime introspection and code generation
capabilities, which are widely used in:
- ORM frameworks (SQLAlchemy, Django models)
- Serialization libraries (Pydantic, dataclasses, attrs)
- RPC/API code generators
- Test parameterization frameworks
"""
import types
import textwrap
def generate_class(name: str, config: dict) -> type:
"""
Generate a class dynamically from a configuration dictionary.
Config format:
{
"fields": {"field_name": default_value, ...},
"methods": {
"method_name": {
"args": ["arg1", "arg2"],
"body": "return arg1 + arg2" # Python expression/statements
},
...
},
"computed": {
"property_name": "self.x * self.y" # Expression using fields
}
}
"""
fields = config.get('fields', {})
methods = config.get('methods', {})
computed = config.get('computed', {})
namespace = {}
# ── Generate __init__ ──────────────────────────────────────────────────
init_params = ', '.join(f'{f}={repr(v)}' for f, v in fields.items())
init_assignments = '\n'.join(f' self.{f} = {f}' for f in fields)
init_source = f"def __init__(self, {init_params}):\n{init_assignments}\n"
exec(compile(init_source, f'<{name}.__init__>', 'exec'), namespace)
# ── Generate __repr__ ─────────────────────────────────────────────────
repr_fields = ', '.join(f'{f}={{self.{f}!r}}' for f in fields)
repr_source = f"def __repr__(self):\n return f'{name}({repr_fields})'\n"
exec(compile(repr_source, f'<{name}.__repr__>', 'exec'), namespace)
# ── Generate user-defined methods ─────────────────────────────────────
for method_name, spec in methods.items():
args = spec.get('args', [])
body = spec['body']
arg_str = ', '.join(['self'] + args)
# Handle multi-line bodies
body_lines = body.strip().split('\n')
indented_body = '\n'.join(f' {line}' for line in body_lines)
method_source = f"def {method_name}({arg_str}):\n{indented_body}\n"
method_ns = {}
exec(compile(method_source, f'<{name}.{method_name}>', 'exec'), method_ns)
namespace[method_name] = method_ns[method_name]
# ── Generate computed properties ──────────────────────────────────────
for prop_name, expression in computed.items():
prop_source = textwrap.dedent(f"""\
@property
def {prop_name}(self):
return {expression}
""")
prop_ns = {'property': property}
exec(compile(prop_source, f'<{name}.{prop_name}>', 'exec'), prop_ns)
namespace[prop_name] = prop_ns[prop_name]
# ── Assemble the class ────────────────────────────────────────────────
cls = type(name, (object,), namespace)
return cls
def demo():
"""Demonstrate dynamic class generation from a configuration dictionary."""
config = {
"fields": {
"x": 0,
"y": 0,
"label": "'point'"
},
"methods": {
"translate": {
"args": ["dx", "dy"],
"body": (
"self.x += dx\n"
"self.y += dy\n"
"return self"
)
},
"distance_to": {
"args": ["other"],
"body": "return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5"
},
"scale": {
"args": ["factor"],
"body": (
"self.x = int(self.x * factor)\n"
"self.y = int(self.y * factor)\n"
"return self"
)
},
"as_tuple": {
"args": [],
"body": "return (self.x, self.y)"
},
"describe": {
"args": [],
"body": "return f'{self.label} at ({self.x}, {self.y}), magnitude={self.magnitude:.2f}'"
}
},
"computed": {
"magnitude": "(self.x ** 2 + self.y ** 2) ** 0.5",
"quadrant": (
"1 if self.x > 0 and self.y > 0 else "
"2 if self.x < 0 and self.y > 0 else "
"3 if self.x < 0 and self.y < 0 else "
"4 if self.x > 0 and self.y < 0 else 0"
)
}
}
print("=" * 70)
print("METAPROGRAMMING DEMO — Dynamic Class Generation")
print("=" * 70)
print("\n[CONFIG DICTIONARY]")
import json
# Pretty-print the config (convert non-serializable parts)
print(json.dumps(config, indent=2))
print("\n[GENERATING CLASS 'Point' FROM CONFIG...]")
Point = generate_class('Point', config)
print(f"\nGenerated class: {Point}")
print(f"MRO: {[c.__name__ for c in Point.__mro__]}")
print(f"Methods: {[m for m in dir(Point) if not m.startswith('_')]}")
print("\n[INSTANTIATION AND METHOD CALLS]")
p1 = Point(x=3, y=4, label="'origin'")
print(f" p1 = {p1}")
print(f" p1.magnitude = {p1.magnitude:.4f}")
print(f" p1.quadrant = {p1.quadrant}")
print(f" p1.as_tuple() = {p1.as_tuple()}")
print(f" p1.describe() = {p1.describe()}")
p2 = Point(x=6, y=8)
print(f"\n p2 = {p2}")
print(f" p1.distance_to(p2) = {p1.distance_to(p2):.4f}")
print(f"\n p1.translate(10, -5) => ", end="")
p1.translate(10, -5)
print(f"{p1}")
print(f" p1.quadrant = {p1.quadrant}")
print(f"\n p1.scale(2) => ", end="")
p1.scale(2)
print(f"{p1}")
print(f" p1.magnitude = {p1.magnitude:.4f}")
# ── Demonstrate that no source code for Point exists ──────────────────
print("\n[INTROSPECTION]")
print(f" type(p1) = {type(p1)}")
print(f" isinstance(p1, Point) = {isinstance(p1, Point)}")
print(f" Point.__module__ = {Point.__module__}")
# Show the dynamically generated method source
import dis
print(f"\n[BYTECODE OF GENERATED 'translate' METHOD]")
dis.dis(Point.translate)
print("\n" + "=" * 70)
print("The Point class, its __init__, methods, and properties were all")
print("generated at runtime from a plain dictionary. No class definition")
print("exists anywhere in the source code.")
print("=" * 70)
if __name__ == '__main__':
demo()