引言:代码即数据,数据即代码
元编程(Metaprogramming)是编写操作代码的代码的能力。Python在这方面提供了丰富的工具,让我们能够在运行时动态地创建、修改和执行代码。这是Python最强大、最神奇的特性之一。
一、动态属性与属性访问控制
1.1 __getattr__ 与 __getattribute__
class DynamicAttributes:
"""动态属性访问示例"""
def __init__(self):
self._data = {}
self._access_count = 0
def __getattr__(self, name):
"""当属性不存在时调用"""
print(f"__getattr__ 被调用: {name}")
# 如果是 "not_found_" 开头的属性,返回一个默认消息
if name.startswith("not_found_"):
return f"属性 {name} 不存在,但这是默认值"
# 其他情况抛出 AttributeError
raise AttributeError(f"'DynamicAttributes' 对象没有属性 '{name}'")
def __getattribute__(self, name):
"""访问任何属性时都会调用(包括存在的属性)"""
# 避免递归调用
if name == "_access_count":
return super().__getattribute__(name)
# 记录访问次数
self._access_count = getattr(self, "_access_count", 0) + 1
print(f"属性访问 #{self._access_count}: {name}")
# 使用 super() 避免递归
return super().__getattribute__(name)
def __setattr__(self, name, value):
"""设置属性时调用"""
print(f"设置属性: {name} = {value}")
# 特殊处理 _data 属性
if name == "_data":
super().__setattr__(name, value)
else:
# 其他属性存储在 _data 字典中
self._data[name] = value
def __delattr__(self, name):
"""删除属性时调用"""
print(f"删除属性: {name}")
if name in self._data:
del self._data[name]
else:
super().__delattr__(name)
# 使用示例
obj = DynamicAttributes()
obj.name = "Python" # 调用 __setattr__
print(obj.name) # 调用 __getattribute__,然后从 _data 中获取
print(obj.age) # 调用 __getattribute__,然后 __getattr__(抛出异常)
print(obj.not_found_age) # 调用 __getattribute__,然后 __getattr__(返回默认值)
# 查看访问统计
print(f"总访问次数: {obj._access_count}")
1.2 描述符(Descriptors)
class ValidatedAttribute:
"""描述符:验证属性值的有效性"""
def __init__(self, validator=None, default=None):
self.validator = validator
self.default = default
self.data = {}
def __get__(self, instance, owner):
"""获取属性值"""
if instance is None:
return self
return self.data.get(id(instance), self.default)
def __set__(self, instance, value):
"""设置属性值,并进行验证"""
if self.validator and not self.validator(value):
raise ValueError(f"无效的值: {value}")
self.data[id(instance)] = value
def __delete__(self, instance):
"""删除属性值"""
del self.data[id(instance)]
class TypedAttribute(ValidatedAttribute):
"""类型检查描述符"""
def __init__(self, expected_type, default=None):
validator = lambda x: isinstance(x, expected_type)
super().__init__(validator, default)
self.expected_type = expected_type
class RangeAttribute(ValidatedAttribute):
"""范围检查描述符"""
def __init__(self, min_value=None, max_value=None, default=None):
def validator(value):
if min_value is not None and value < min_value:
return False
if max_value is not None and value > max_value:
return False
return True
super().__init__(validator, default)
self.min_value = min_value
self.max_value = max_value
class Person:
"""使用描述符的类"""
# 类型检查
name = TypedAttribute(str, "")
age = TypedAttribute(int, 0)
# 范围检查
score = RangeAttribute(min_value=0, max_value=100, default=60)
def __init__(self, name="", age=0, score=60):
self.name = name
self.age = age
self.score = score
def __str__(self):
return f"Person(name={self.name}, age={self.age}, score={self.score})"
# 测试描述符
p1 = Person()
print(f"默认值: {p1}")
p1.name = "Alice"
p1.age = 25
p1.score = 85
print(f"设置后: {p1}")
try:
p1.name = 123 # 应该失败:类型错误
except ValueError as e:
print(f"类型检查: {e}")
try:
p1.score = 150 # 应该失败:超出范围
except ValueError as e:
print(f"范围检查: {e}")
# 验证描述符的工作方式
print(f"\n描述符实例: {Person.name}")
print(f"描述符类型: {type(Person.name)}")
print(f"Person类上的name属性: {Person.__dict__['name']}")
# 多个实例共享同一个描述符,但数据隔离
p2 = Person("Bob", 30, 90)
print(f"\nPerson 1: {p1.name}, {p1.age}, {p1.score}")
print(f"Person 2: {p2.name}, {p2.age}, {p2.score}")
1.3 属性(property)的高级用法
class Temperature:
"""使用property实现温度转换"""
def __init__(self, celsius=0):
self._celsius = celsius
@property
def celsius(self):
"""摄氏度属性"""
print("获取摄氏度")
return self._celsius
@celsius.setter
def celsius(self, value):
"""设置摄氏度"""
print(f"设置摄氏度: {value}")
if value < -273.15:
raise ValueError("温度不能低于绝对零度")
self._celsius = value
@property
def fahrenheit(self):
"""华氏度属性(只读)"""
print("计算华氏度")
return self._celsius * 9/5 + 32
@property
def kelvin(self):
"""开尔文属性(只读)"""
print("计算开尔文")
return self._celsius + 273.15
@kelvin.setter
def kelvin(self, value):
"""通过开尔文设置温度"""
print(f"通过开尔文设置温度: {value}")
self.celsius = value - 273.15
# 使用示例
temp = Temperature(25)
print(f"摄氏度: {temp.celsius}")
print(f"华氏度: {temp.fahrenheit}")
print(f"开尔文: {temp.kelvin}")
temp.celsius = 30
print(f"新华氏度: {temp.fahrenheit}")
temp.kelvin = 300
print(f"新摄氏度: {temp.celsius}")
# property的本质
print(f"\nproperty类型: {type(Temperature.celsius)}")
print(f"property描述符: {Temperature.celsius}")
print(f"fget方法: {Temperature.celsius.fget}")
print(f"fset方法: {Temperature.celsius.fset}")
# 动态创建property
class DynamicPropertyClass:
"""动态添加property"""
def __init__(self):
self._values = {}
def add_property(self, name, default=None):
"""动态添加一个property"""
# 创建getter和setter
def getter(self):
return self._values.get(name, default)
def setter(self, value):
self._values[name] = value
# 创建property
prop = property(getter, setter)
# 添加到类中
setattr(self.__class__, name, prop)
# 测试动态property
obj = DynamicPropertyClass()
obj.add_property("dynamic_attr", "default_value")
obj.add_property("count", 0)
print(f"\n动态属性1: {obj.dynamic_attr}")
obj.dynamic_attr = "new_value"
print(f"动态属性1修改后: {obj.dynamic_attr}")
print(f"动态属性2: {obj.count}")
obj.count = 42
print(f"动态属性2修改后: {obj.count}")
二、元类(Metaclass)
2.1 理解元类:类的类
# 最简单的元类示例
class SimpleMeta(type):
"""简单的元类"""
def __new__(mcs, name, bases, namespace):
"""创建类时调用"""
print(f"元类 __new__ 被调用:")
print(f" 元类: {mcs}")
print(f" 类名: {name}")
print(f" 基类: {bases}")
print(f" 命名空间: {namespace.keys()}")
# 修改命名空间:添加一个类属性
namespace['created_by_meta'] = True
# 调用type的__new__来实际创建类
return super().__new__(mcs, name, bases, namespace)
def __init__(cls, name, bases, namespace):
"""初始化类时调用"""
print(f"元类 __init__ 被调用: 初始化类 {cls}")
super().__init__(name, bases, namespace)
def __call__(cls, *args, **kwargs):
"""创建类的实例时调用"""
print(f"元类 __call__ 被调用: 创建 {cls} 的实例")
# 可以在创建实例前做一些事情
print(f" 参数: args={args}, kwargs={kwargs}")
# 调用类的__new__和__init__
instance = super().__call__(*args, **kwargs)
# 可以在创建实例后做一些事情
print(f" 创建的实例: {instance}")
return instance
# 使用元类创建类
class MyClass(metaclass=SimpleMeta):
"""使用SimpleMeta元类的类"""
class_attribute = "类属性"
def __init__(self, value):
self.value = value
print(f"MyClass __init__ 被调用: value={value}")
def __str__(self):
return f"MyClass(value={self.value})"
print("\n" + "="*50)
print("创建类实例:")
print("="*50)
# 创建实例时,元类的__call__会被调用
obj = MyClass("测试值")
print(f"\n类属性: {MyClass.created_by_meta}")
print(f"实例属性: {obj.value}")
# 查看类和元类的关系
print(f"\nMyClass的类型: {type(MyClass)}")
print(f"MyClass的元类: {MyClass.__class__}")
print(f"元类的类型: {type(SimpleMeta)}")
print(f"元类的基类: {SimpleMeta.__bases__}")
2.2 实际应用:自动注册子类
class PluginMeta(type):
"""插件系统元类:自动注册所有子类"""
# 注册表
_registry = {}
def __new__(mcs, name, bases, namespace):
"""创建类时自动注册"""
cls = super().__new__(mcs, name, bases, namespace)
# 跳过基类
if name != "PluginBase":
plugin_name = namespace.get('plugin_name', name.lower())
mcs._registry[plugin_name] = cls
print(f"注册插件: {plugin_name} -> {cls.__name__}")
return cls
@classmethod
def get_plugin(mcs, name):
"""获取插件类"""
return mcs._registry.get(name)
@classmethod
def list_plugins(mcs):
"""列出所有插件"""
return list(mcs._registry.keys())
class PluginBase(metaclass=PluginMeta):
"""插件基类"""
def run(self):
raise NotImplementedError
class InputPlugin(PluginBase):
"""输入插件"""
plugin_name = "input"
def run(self):
return "处理输入..."
class OutputPlugin(PluginBase):
"""输出插件"""
plugin_name = "output"
def run(self):
return "处理输出..."
class TransformPlugin(PluginBase):
"""转换插件"""
# 如果没有指定plugin_name,使用类名小写
def run(self):
return "转换数据..."
class FilterPlugin(PluginBase):
"""过滤插件"""
plugin_name = "filter"
def run(self):
return "过滤数据..."
# 使用插件系统
print(f"\n可用插件: {PluginMeta.list_plugins()}")
# 动态创建插件实例
plugin_type = PluginMeta.get_plugin("input")
if plugin_type:
plugin = plugin_type()
print(f"运行插件: {plugin.run()}")
# 遍历所有插件
print("\n运行所有插件:")
for plugin_name in PluginMeta.list_plugins():
plugin_class = PluginMeta.get_plugin(plugin_name)
plugin = plugin_class()
print(f" {plugin_name}: {plugin.run()}")
2.3 动态创建类
def create_class(class_name, base_classes=None, attributes=None):
"""动态创建类"""
if base_classes is None:
base_classes = (object,)
if attributes is None:
attributes = {}
# 准备命名空间
namespace = {
'__module__': __name__,
'__qualname__': class_name,
}
namespace.update(attributes)
# 使用type创建类
new_class = type(class_name, base_classes, namespace)
return new_class
# 动态创建类
DynamicPerson = create_class(
"DynamicPerson",
attributes={
"species": "Human",
"__init__": lambda self, name: setattr(self, "name", name),
"greet": lambda self: f"Hello, I'm {self.name}",
"__str__": lambda self: f"DynamicPerson(name={self.name})"
}
)
# 使用动态创建的类
person = DynamicPerson("Alice")
print(f"动态类实例: {person}")
print(f"调用方法: {person.greet()}")
print(f"类属性: {person.species}")
# 更复杂的动态类创建
def create_data_class(class_name, fields):
"""创建类似dataclass的数据类"""
def __init__(self, *args, **kwargs):
"""动态生成的__init__方法"""
# 处理位置参数
for i, field in enumerate(fields):
if i < len(args):
setattr(self, field, args[i])
elif field in kwargs:
setattr(self, field, kwargs[field])
else:
setattr(self, field, None)
def __repr__(self):
"""动态生成的__repr__方法"""
field_values = ', '.join(
f"{field}={getattr(self, field)}"
for field in fields
)
return f"{class_name}({field_values})"
# 创建属性访问方法
methods = {
"__init__": __init__,
"__repr__": __repr__,
}
# 为每个字段创建property
for field in fields:
methods[field] = property(
lambda self, f=field: getattr(self, f"_get_{f}", lambda: None)(),
lambda self, value, f=field: getattr(self, f"_set_{f}", lambda v: None)(value)
)
return type(class_name, (object,), methods)
# 创建数据类
User = create_data_class("User", ["name", "email", "age"])
user = User("Bob", "bob@example.com", 30)
print(f"\n动态数据类: {user}")
print(f"属性访问: name={user.name}, age={user.age}")
三、装饰器工厂与类装饰器
3.1 装饰器工厂
from functools import wraps
from datetime import datetime
import time
def decorator_factory(level="INFO", log_file=None):
"""装饰器工厂:创建带参数的装饰器"""
def decorator(func):
"""实际的装饰器"""
@wraps(func)
def wrapper(*args, **kwargs):
# 记录日志
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
log_msg = f"[{level}] {timestamp} - {func.__name__}被调用"
if log_file:
with open(log_file, "a") as f:
f.write(log_msg + "\n")
else:
print(log_msg)
# 执行函数
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
# 记录执行时间
duration_msg = f"[{level}] {timestamp} - {func.__name__}执行时间: {end_time-start_time:.4f}秒"
if log_file:
with open(log_file, "a") as f:
f.write(duration_msg + "\n")
else:
print(duration_msg)
return result
return wrapper
return decorator
# 使用装饰器工厂
@decorator_factory(level="DEBUG")
def debug_function():
"""调试函数"""
time.sleep(0.1)
return "调试完成"
@decorator_factory(level="ERROR", log_file="error.log")
def error_function():
"""错误函数"""
time.sleep(0.05)
raise ValueError("模拟错误")
# 测试
print("测试装饰器工厂:")
result = debug_function()
print(f"结果: {result}")
try:
error_function()
except ValueError as e:
print(f"捕获错误: {e}")
# 读取日志文件
with open("error.log", "r") as f:
print(f"\n错误日志内容:\n{f.read()}")
3.2 类装饰器
class SingletonDecorator:
"""单例类装饰器"""
def __init__(self, cls):
self.cls = cls
self._instance = None
def __call__(self, *args, **kwargs):
"""使类成为单例"""
if self._instance is None:
self._instance = self.cls(*args, **kwargs)
return self._instance
@SingletonDecorator
class DatabaseConnection:
"""数据库连接类(单例)"""
def __init__(self, connection_string):
self.connection_string = connection_string
print(f"创建数据库连接: {connection_string}")
self._connected = False
def connect(self):
self._connected = True
return f"连接到: {self.connection_string}"
# 测试单例
print("测试单例装饰器:")
db1 = DatabaseConnection("mysql://localhost:3306/mydb")
db2 = DatabaseConnection("mysql://localhost:3306/otherdb")
print(f"db1 is db2: {db1 is db2}")
print(f"db1.connection_string: {db1.connection_string}")
print(f"db2.connection_string: {db2.connection_string}")
class ValidateAttributesDecorator:
"""验证类属性的装饰器"""
def __init__(self, cls):
self.cls = cls
def __call__(self, *args, **kwargs):
"""创建实例时验证属性"""
instance = self.cls(*args, **kwargs)
self._validate_attributes(instance)
return instance
def _validate_attributes(self, instance):
"""验证所有以'_validate_'开头的方法"""
for attr_name in dir(instance):
if attr_name.startswith("_validate_"):
validator = getattr(instance, attr_name)
if callable(validator):
field_name = attr_name[10:] # 去掉'_validate_'
value = getattr(instance, field_name, None)
if not validator(value):
raise ValueError(f"属性 {field_name} 验证失败: {value}")
@ValidateAttributesDecorator
class User:
"""用户类,属性会被自动验证"""
def __init__(self, name, age, email):
self.name = name
self.age = age
self.email = email
def _validate_name(self, value):
"""验证姓名"""
return isinstance(value, str) and len(value) >= 2
def _validate_age(self, value):
"""验证年龄"""
return isinstance(value, int) and 0 <= value <= 150
def _validate_email(self, value):
"""验证邮箱(简化)"""
return isinstance(value, str) and "@" in value
print("\n测试属性验证装饰器:")
try:
user1 = User("Alice", 25, "alice@example.com")
print(f"用户1创建成功: {user1.name}")
except ValueError as e:
print(f"用户1创建失败: {e}")
try:
user2 = User("A", 200, "invalid-email")
print(f"用户2创建成功: {user2.name}")
except ValueError as e:
print(f"用户2创建失败: {e}")
四、代码生成与动态导入
4.1 使用exec和eval
import ast
import math
def safe_exec(code_string, globals_dict=None, locals_dict=None):
"""安全执行代码,限制可访问的模块"""
if globals_dict is None:
globals_dict = {}
# 安全的全局命名空间
safe_globals = {
'__builtins__': {
'print': print,
'len': len,
'range': range,
'list': list,
'dict': dict,
'int': int,
'str': str,
'float': float,
'bool': bool,
'sum': sum,
'max': max,
'min': min,
'abs': abs,
'round': round,
'math': math, # 允许使用math模块
}
}
safe_globals.update(globals_dict)
# 执行代码
try:
# 先编译检查语法
compiled = compile(code_string, '<string>', 'exec')
# 在限制的环境中执行
exec(compiled, safe_globals, locals_dict)
# 返回结果
return safe_globals.get('result', None)
except Exception as e:
return f"执行错误: {e}"
def dynamic_calculator(expression, variables=None):
"""动态计算器"""
if variables is None:
variables = {}
# 构建计算代码
code = f"""
result = {expression}
"""
# 执行计算
return safe_exec(code, variables)
# 使用示例
print("动态计算器示例:")
variables = {'x': 10, 'y': 20, 'z': 30}
# 简单计算
result = dynamic_calculator("x + y * z", variables)
print(f"x + y * z = {result}")
# 使用数学函数
result = dynamic_calculator("math.sin(math.pi / 2)", variables)
print(f"sin(π/2) = {result}")
# 复杂表达式
result = dynamic_calculator("sum([x, y, z]) / len([x, y, z])", variables)
print(f"平均值 = {result}")
def generate_class_dynamically(class_name, methods_dict):
"""动态生成类"""
# 构建类定义代码
imports = """
from datetime import datetime
import json
"""
# 生成方法代码
methods_code = []
for method_name, method_body in methods_dict.items():
method_code = f"""
def {method_name}(self, *args, **kwargs):
{method_body}
"""
methods_code.append(method_code)
# 完整的类代码
class_code = f"""
{imports}
class {class_name}:
def __init__(self, name):
self.name = name
self.created_at = datetime.now()
def __str__(self):
return f"{class_name}(name={{self.name}})"
def to_json(self):
return json.dumps({{
'name': self.name,
'created_at': self.created_at.isoformat()
}})
{''.join(methods_code)}
"""
# 执行代码生成类
namespace = {}
exec(class_code, namespace)
return namespace[class_name]
# 动态生成类
DynamicGeneratedClass = generate_class_dynamically(
"DynamicService",
{
"greet": '''return f"Hello, {self.name}!"''',
"process_data": '''return sum(args) if args else 0''',
"validate_input": '''return kwargs.get("valid", False)'''
}
)
# 使用动态生成的类
service = DynamicGeneratedClass("TestService")
print(f"\n动态生成的类实例: {service}")
print(f"调用方法1: {service.greet()}")
print(f"调用方法2: {service.process_data(1, 2, 3, 4, 5)}")
print(f"调用方法3: {service.validate_input(valid=True)}")
print(f"JSON表示: {service.to_json()}")
4.2 AST(抽象语法树)操作
import ast
import inspect
class CodeTransformer(ast.NodeTransformer):
"""代码转换器:修改AST"""
def visit_FunctionDef(self, node):
"""访问函数定义节点"""
# 重命名函数(添加前缀)
node.name = f"transformed_{node.name}"
# 添加装饰器
decorator = ast.Name(id='staticmethod', ctx=ast.Load())
node.decorator_list.append(decorator)
# 添加文档字符串
if not ast.get_docstring(node):
docstring = ast.Expr(value=ast.Constant(value="动态添加的文档字符串"))
node.body.insert(0, docstring)
# 继续处理子节点
self.generic_visit(node)
return node
def visit_Call(self, node):
"""访问函数调用节点"""
# 将所有的print改为大写PRINT
if isinstance(node.func, ast.Name) and node.func.id == 'print':
node.func.id = 'PRINT'
# 继续处理子节点
self.generic_visit(node)
return node
def transform_code(source_code):
"""转换源代码"""
# 解析为AST
tree = ast.parse(source_code)
# 应用转换器
transformer = CodeTransformer()
transformed_tree = transformer.visit(tree)
# 添加缺失的行号信息
ast.fix_missing_locations(transformed_tree)
# 编译并执行
code_object = compile(transformed_tree, '<transformed>', 'exec')
# 创建新的命名空间
namespace = {'PRINT': print} # 提供PRINT函数
# 执行转换后的代码
exec(code_object, namespace)
return namespace
# 要转换的源代码
original_code = """
def hello(name):
print(f"Hello, {name}!")
def calculate(a, b):
result = a + b
print(f"结果: {result}")
return result
"""
print("AST转换示例:")
print("原始代码:")
print(original_code)
print("\n转换后的代码执行结果:")
namespace = transform_code(original_code)
# 调用转换后的函数
try:
# 函数名被修改了
namespace['transformed_hello']("World")
result = namespace['transformed_calculate'](10, 20)
print(f"计算结果: {result}")
except KeyError as e:
print(f"找不到函数: {e}")
def analyze_function(func):
"""分析函数的AST"""
# 获取源代码
source = inspect.getsource(func)
# 解析为AST
tree = ast.parse(source)
# 分析AST
analyzer = ASTAnalyzer()
analyzer.visit(tree)
return analyzer.report()
class ASTAnalyzer(ast.NodeVisitor):
"""AST分析器"""
def __init__(self):
self.functions = []
self.calls = []
self.variables = set()
self.imports = []
def visit_FunctionDef(self, node):
"""分析函数定义"""
self.functions.append({
'name': node.name,
'args': [arg.arg for arg in node.args.args],
'lineno': node.lineno,
'docstring': ast.get_docstring(node)
})
self.generic_visit(node)
def visit_Call(self, node):
"""分析函数调用"""
if isinstance(node.func, ast.Name):
self.calls.append(node.func.id)
self.generic_visit(node)
def visit_Name(self, node):
"""分析变量名"""
if isinstance(node.ctx, ast.Store): # 赋值
self.variables.add(node.id)
self.generic_visit(node)
def visit_Import(self, node):
"""分析导入"""
for alias in node.names:
self.imports.append(alias.name)
self.generic_visit(node)
def visit_ImportFrom(self, node):
"""分析from...import"""
for alias in node.names:
self.imports.append(f"{node.module}.{alias.name}")
self.generic_visit(node)
def report(self):
"""生成分析报告"""
return {
'functions': self.functions,
'calls': list(set(self.calls)),
'variables': list(self.variables),
'imports': self.imports
}
# 分析示例函数
def example_function(x, y):
"""示例函数"""
import math
result = x + y
z = math.sqrt(result)
print(f"计算结果: {z}")
return z
print("\nAST分析示例:")
analysis = analyze_function(example_function)
print(f"函数分析: {analysis['functions']}")
print(f"函数调用: {analysis['calls']}")
print(f"变量: {analysis['variables']}")
print(f"导入: {analysis['imports']}")
五、实际应用:ORM框架的实现
class Field:
"""ORM字段基类"""
def __init__(self, field_type, primary_key=False, nullable=True, default=None):
self.field_type = field_type
self.primary_key = primary_key
self.nullable = nullable
self.default = default
def __str__(self):
return f"Field(type={self.field_type.__name__})"
class ModelMeta(type):
"""Model的元类"""
def __new__(mcs, name, bases, namespace):
# 跳过基类
if name == "Model":
return super().__new__(mcs, name, bases, namespace)
# 收集字段
fields = {}
for key, value in list(namespace.items()):
if isinstance(value, Field):
fields[key] = value
# 从命名空间中移除字段,避免成为类属性
del namespace[key]
# 创建类
cls = super().__new__(mcs, name, bases, namespace)
# 设置元数据
cls._fields = fields
cls._table_name = namespace.get('__table__', name.lower())
# 生成__init__方法
mcs._create_init_method(cls, fields)
# 生成SQL创建语句
cls._create_table_sql = mcs._generate_create_table_sql(cls)
return cls
@staticmethod
def _create_init_method(cls, fields):
"""动态生成__init__方法"""
def __init__(self, **kwargs):
self._data = {}
# 设置字段值
for field_name, field in fields.items():
value = kwargs.get(field_name)
if value is None and field.default is not None:
value = field.default() if callable(field.default) else field.default
if value is None and not field.nullable and not field.primary_key:
raise ValueError(f"字段 {field_name} 不能为None")
setattr(self, field_name, value)
cls.__init__ = __init__
@staticmethod
def _generate_create_table_sql(cls):
"""生成创建表的SQL语句"""
columns = []
for field_name, field in cls._fields.items():
column_def = f"{field_name} {field.field_type}"
if field.primary_key:
column_def += " PRIMARY KEY"
if not field.nullable:
column_def += " NOT NULL"
if field.default is not None:
default_value = field.default() if callable(field.default) else field.default
column_def += f" DEFAULT {repr(default_value)}"
columns.append(column_def)
sql = f"CREATE TABLE IF NOT EXISTS {cls._table_name} (\n"
sql += ",\n".join(f" {col}" for col in columns)
sql += "\n);"
return sql
class Model(metaclass=ModelMeta):
"""ORM模型基类"""
def __init__(self, **kwargs):
pass
def save(self):
"""保存到数据库(模拟)"""
print(f"保存 {self.__class__.__name__} 到数据库")
print(f"数据: {self._data}")
@classmethod
def create_table(cls):
"""创建表(模拟)"""
print(f"创建表 {cls._table_name}:")
print(cls._create_table_sql)
def __str__(self):
fields_str = ", ".join(
f"{name}={getattr(self, name)}"
for name in self._fields.keys()
)
return f"{self.__class__.__name__}({fields_str})"
# 定义具体的模型类
class User(Model):
"""用户模型"""
__table__ = "users"
id = Field(int, primary_key=True)
username = Field(str, nullable=False)
email = Field(str, nullable=False)
age = Field(int, nullable=True, default=18)
created_at = Field(str, default=lambda: "2024-01-01")
class Product(Model):
"""产品模型"""
__table__ = "products"
id = Field(int, primary_key=True)
name = Field(str, nullable=False)
price = Field(float, nullable=False)
stock = Field(int, default=0)
# 使用ORM
print("ORM框架示例:")
# 查看生成的SQL
print("\n1. 创建表的SQL:")
User.create_table()
Product.create_table()
# 创建实例
print("\n2. 创建模型实例:")
user1 = User(id=1, username="alice", email="alice@example.com")
print(f"用户1: {user1}")
user2 = User(id=2, username="bob", email="bob@example.com", age=25)
print(f"用户2: {user2}")
product1 = Product(id=101, name="Python Book", price=59.99, stock=100)
print(f"产品1: {product1}")
# 保存到数据库
print("\n3. 保存到数据库:")
user1.save()
product1.save()
# 验证元数据
print("\n4. 模型元数据:")
print(f"User表名: {User._table_name}")
print(f"User字段: {list(User._fields.keys())}")
print(f"User字段类型: {{name: type(field.field_type).__name__ for name, field in User._fields.items()}}")
# 尝试无效数据
print("\n5. 验证数据约束:")
try:
invalid_user = User(id=3) # 缺少必填字段
except ValueError as e:
print(f"验证失败: {e}")
总结
Python元编程提供了强大的工具来操作代码本身:
- 动态属性:通过
__getattr__、__getattribute__、描述符等控制属性访问 - 元类:控制类的创建过程,实现自动注册、验证等高级功能
- 装饰器工厂:创建可配置的装饰器,增强函数或类的功能
- 动态代码生成:使用
exec、eval、AST 操作在运行时生成和修改代码
元编程的关键原则:
- 谨慎使用:元编程增加了复杂性,只在必要时使用
- 保持可读性:确保生成的代码可读可维护
- 安全性第一:动态执行代码时要特别注意安全性
- 了解原理:深入理解 Python 的对象模型和查找机制