Python 高级与进阶主题 深度解析
目录
- 元类与类的创建
- 1.1 什么是元类
- 1.2 自定义元类
- 1.3 元类的实际应用
- 描述符:属性背后的魔法
- 2.1 描述符协议
- 2.2 数据描述符与非数据描述符
- 2.3 描述符的应用:属性、方法绑定
- 内存管理与垃圾回收
- 3.1 引用计数
- 3.2 分代回收
- 3.3 弱引用
weakref
- 性能优化与剖析
- 4.1 时间测量:
timeit与cProfile - 4.2 高效代码实践
- 4.3
functools.lru_cache与@lru_cache
- 4.1 时间测量:
- C 扩展:ctypes 与 Cython
- 5.1 ctypes 调用动态库
- 5.2 Cython:Python 的超集
- 深入了解 Python 解释器
- 6.1 Python 字节码与
dis模块 - 6.2 内存布局与对象模型
- 6.1 Python 字节码与
- 微服务与 RPC 简介
- 7.1 gRPC 快速上手
- 7.2 微服务框架选型
- 总结
1. 元类与类的创建
1.1 什么是元类
在 Python 中,一切皆对象——类本身也是对象。类的类型就是元类,默认元类是 type。使用 type() 不仅能查看对象的类型,还能动态创建新类。
# type 创建类
MyClass = type('MyClass', (object,), {'x': 10, 'show': lambda self: self.x})
obj = MyClass()
print(obj.show()) # 10
1.2 自定义元类
自定义元类需要继承 type,并重写 __new__ 或 __init__,从而在类被创建时对其属性、方法进行校验或修改。
# 元类:强制类名大写
class CapsNameMeta(type):
def __new__(cls, name, bases, dct):
if not name.isupper():
raise ValueError(f"类名 {name} 必须全大写")
return super().__new__(cls, name, bases, dct)
class USER(metaclass=CapsNameMeta):
pass
# class user(metaclass=CapsNameMeta): # 将抛出 ValueError
# pass
1.3 元类的实际应用
- ORM 框架(如 Django models)使用元类自动收集模型字段。
- 单例模式:通过元类控制实例的唯一性。
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Singleton(metaclass=SingletonMeta):
pass
a = Singleton()
b = Singleton()
print(a is b) # True
2. 描述符:属性背后的魔法
2.1 描述符协议
一个类实现了 __get__、__set__、__delete__ 中任意方法,其实例就是描述符,用来代理另一个类的属性访问。
class PositiveNumber:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, owner):
return obj.__dict__[self.name]
def __set__(self, obj, value):
if value < 0:
raise ValueError(f"{self.name} 必须为正数")
obj.__dict__[self.name] = value
class Item:
price = PositiveNumber()
def __init__(self, price):
self.price = price
item = Item(10)
# item.price = -5 # ValueError
2.2 数据描述符与非数据描述符
- 数据描述符:同时定义了
__get__和__set__(或__delete__),优先级高于实例字典。 - 非数据描述符:仅定义
__get__,实例字典优先级更高。
property是数据描述符,staticmethod、classmethod是非数据描述符。
2.3 描述符的应用:属性、方法绑定
@property本质是描述符。- 普通过函数作为类方法时,通过非数据描述符机制绑定
self。这也是为何能在方法中自动传入实例的原理。
3. 内存管理与垃圾回收
3.1 引用计数
Python 主要使用引用计数管理内存。sys.getrefcount() 可查看引用数(自身会临时增加一次引用)。
import sys
a = []
b = a
print(sys.getrefcount(a)) # 3(a, b, getrefcount参数)
引用计数无法处理循环引用,必须由分代回收机制解决。
3.2 分代回收
gc 模块处理循环引用。对象划分为三个代(0、1、2),大多数对象不可达很快回收。
import gc
print(gc.get_threshold()) # (700, 10, 10)
gc.collect() # 手动触发全量回收
3.3 弱引用 weakref
弱引用不会增加引用计数,避免循环引用导致的内存泄漏,常用于缓存。
import weakref
class CacheEntry:
def __init__(self, data):
self.data = data
# 弱引用字典,当对象被回收时自动移除
cache = weakref.WeakValueDictionary()
key = "obj"
cache[key] = CacheEntry("important")
obj = cache.get(key)
del obj
# 内存回收后,cache[key] 可能返回 None
4. 性能优化与剖析
4.1 时间测量:timeit 与 cProfile
- timeit:精确度量小段代码执行时间。
- cProfile:分析函数调用耗时和次数。
python -m timeit "sum(range(1000))"
python -m cProfile script.py
4.2 高效代码实践
- 优先使用内置函数和数据结构(如列表推导、
map、filter)。 - 局部变量比全局变量快;函数内常用变量赋给局部变量。
- 避免在循环中重复点号运算,如
obj.method,提前本地引用。
# 效率对比示例
import math
lst = range(10000)
# 较慢
res = [math.sqrt(x) for x in lst]
# 较快:本地化引用
sqrt = math.sqrt
res = [sqrt(x) for x in lst]
4.3 functools.lru_cache 与 @lru_cache
缓存重复计算的结果,极大加速递归或重复调用。
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
print(fib(100)) # 瞬间完成
5. C 扩展:ctypes 与 Cython
5.1 ctypes 调用动态库
无需编写 C 代码包装,直接加载 .so / .dll 并调用函数。
from ctypes import CDLL, c_double
lib = CDLL("./mylib.so") # Linux
lib.c_function.argtypes = [c_double, c_double]
lib.c_function.restype = c_double
result = lib.c_function(3.0, 4.0)
5.2 Cython:Python 的超集
允许在 Python 中嵌入静态类型声明,编译成 C 扩展模块,获得 C 级性能。
# example.pyx
def sum_int(int n):
cdef int i, total = 0
for i in range(n):
total += i
return total
编译后可直接从 Python 导入使用。
6. 深入了解 Python 解释器
6.1 Python 字节码与 dis 模块
Python 代码先编译成字节码,再由解释器执行。dis 模块能将函数反汇编为字节码指令。
import dis
def add(a, b):
return a + b
dis.dis(add)
# 输出类似:LOAD_FAST, LOAD_FAST, BINARY_ADD, RETURN_VALUE
6.2 内存布局与对象模型
所有 Python 对象都有一个引用计数和类型指针。sys.getsizeof() 可查看对象占用的内存。
import sys
print(sys.getsizeof(42)) # 28 字节(int)
print(sys.getsizeof("hello")) # 54 字节(str)
7. 微服务与 RPC 简介
7.1 gRPC 快速上手
gRPC 使用协议缓冲定义服务,支持多语言。
- 定义
.proto文件。 - 生成 Python 代码。
- 实现服务端与客户端。
服务定义 hello.proto:
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }
Python 服务端示例:
import grpc
import hello_pb2, hello_pb2_grpc
from concurrent import futures
class Greeter(hello_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return hello_pb2.HelloReply(message=f"Hello, {request.name}")
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
7.2 微服务框架选型
- FastAPI + gRPC:适合高性能内部服务通信。
- Nameko:专为 Python 微服务设计,依赖 RabbitMQ。
- aiohttp:轻量级异步服务。
微服务架构通常结合容器化(Docker)和编排(Kubernetes)部署。
8. 总结
掌握 Python 高级主题能让你突破日常开发的边界:元类和描述符解释了许多“魔法”背后的机制;内存管理和弱引用帮助你构建更健壮的长时运行程序;性能剖析与优化工具让代码更快;C 扩展让你在必要时获得 C 级性能;理解解释器内部和字节码则让你成为一个更全面的开发者。这些知识不仅是面试亮点,更是构建大型系统、框架和库的基石。根据自己的兴趣和项目需求,有选择地深入这些领域,你的 Python 内力将踏上一个新台阶。
2万+

被折叠的 条评论
为什么被折叠?



