前言
Python的自省机制(Introspection)是指程序在运行时能够检查自身结构的能力。这意味着你可以获取关于对象的信息,如类定义、属性、方法等,并且可以在运行时动态地操作它们。Python提供了多种内置函数和属性来支持自省功能。
图片
基础示例
1. dir() 函数
dir() 是一个内置函数,它可以列出一个对象的所有属性和方法。
class MyClass:def __init__(self, value):self.value = valuedef my_method(self):pass
obj = MyClass(10)
print(dir(obj)) # 输出所有属性和方法,包括从object继承的
2. getattr() 和 setattr()
这两个函数分别用来获取和设置对象的属性值。
obj = MyClass(20)
print(getattr(obj, 'value')) # 获取属性'value'
setattr(obj, 'value', 30) # 设置属性'value'
print(obj.value) # 输出: 30
3. hasattr() 函数
检查对象是否有指定的属性。
print(hasattr(obj, 'value')) # 输出: True
print(hasattr(obj, 'nonexistent')) # 输出: False
4. delattr() 函数
删除对象的属性。
delattr(obj, 'value')
print(hasattr(obj, 'value')) # 输出: False
5. dict 属性
__dict__
属性是一个字典,包含了类的所有属性。
print(obj.__dict__) # 输出类的属性字典
6. doc 属性
__doc__
属性包含类或方法的文档字符串。
print(MyClass.__doc__) # 如果定义了文档字符串,则输出文档字符串
7. module 属性
__module__
属性显示类定义所在的模块名称。
print(MyClass.__module__) # 输出模块名,通常是文件名
8. bases 属性
__bases__
属性显示类的基类。
print(MyClass.__bases__) # 输出基类,通常是 (object,)
9. type() 函数
type() 函数可以返回一个对象的类型,也可以用来创建新的类实例。
print(type(obj)) # 输出:
10. inspect 模块
Python的inspect模块提供了更深入的自省工具,例如查看函数签名等。
import inspect
def example_function():"""This is an example function."""pass
print(inspect.signature(example_function)) # 输出函数签名
print(inspect.getdoc(example_function)) # 输出函数文档字符串
通过上述方法,你可以动态地了解对象的信息,这对于编写元编程(meta-programming)代码非常有用,尤其是在需要根据运行时条件改变程序行为的情况下。
高阶示例
动态添加方法到类
这个示例展示了如何在运行时动态地向类添加方法。
def dynamic_method(self):print(f"Hello from {self.name}")
class Person:def __init__(self, name):self.name = name
# 动态添加方法
setattr(Person, 'greet', dynamic_method)
# 使用Person类
p = Person("Alice")
p.greet() # 输出: Hello from Alice
使用__slots__
优化内存使用
__slots__
是一个特殊的类属性,用于指定类实例可以拥有的属性。这可以减少内存消耗,并提高属性访问的速度。
class Employee:__slots__ = ('name', 'job_title', 'salary')def __init__(self, name, job_title, salary):self.name = nameself.job_title = job_titleself.salary = salary
# 使用Employee类
e = Employee("Bob", "Developer", 50000)
print(e.name) # 输出: Bob
# 试图添加不在__slots__中的属性会抛出异常
try:e.age = 30
except AttributeError as e:print(e) # 输出: 'Employee' object has no attribute 'age'
使用__getattr__
和__setattr__
重写属性访问
这些特殊方法允许你在访问或设置属性时执行自定义逻辑。
class LazyProperty:def __init__(self, func):self.func = funcdef __get__(self, instance, cls):if instance is None:return selfvalue = self.func(instance)setattr(instance, self.func.__name__, value)return value
class Circle:def __init__(self, radius):self.radius = radius@LazyPropertydef area(self):import mathreturn math.pi * self.radius ** 2
c = Circle(5)
print(c.area) # 第一次计算并存储结果
print(c.area) # 直接返回已存储的结果
使用__getattribute__
拦截所有属性访问
__getattribute__
方法允许你在每次属性被访问时进行拦截。
class LoggingObject:def __getattribute__(self, name):print(f"Accessing attribute: {name}")return super().__getattribute__(name)def __init__(self, value):self.value = value
obj = LoggingObject(42)
print(obj.value) # 输出: Accessing attribute: value# 输出: 42
使用元类(Meta Class)
元类是创建类的类,可以用来定制类的行为。
class Meta(type):def __new__(cls, name, bases, attrs):attrs['class_name'] = name # 添加一个属性return super().__new__(cls, name, bases, attrs)
class MyClass(metaclass=Meta):pass
# 使用MyClass类
mc = MyClass()
print(mc.class_name) # 输出: MyClass
原创 huaan9527 测试开发学习交流