Python面试官:什么是自省

Python 自省:深入了解对象与类型

引语

曾子曰:吾日三省吾身。

概念

编程中,自省Introspection)/反射是指在运行时检查对象的能力,Python 提供了丰富的自省机制,使开发者能够动态地获取有关对象、类型、属性、方法等信息。

在 Python 中,自省的用途非常广泛,包括但不限于调试、序列化、ORM(对象关系映射)等。

常见自省

类型自省type

type() 函数用于返回对象的类型。它是自省的基本工具,可以用于检查变量或对象的类型。比如下面:

x = 100
print(type(x))  # 输出 <class 'int'>

y = "Hello,Python"
print(type(y))  # 输出 <class 'str'>

z = {"a": 1}
print(type(z))  # 输出 <class 'dict'>

# 内建函数 dict 严格上讲是一个继承 object 的类
# 而且所有类(注意:不是类的实例)的类型都是 type
print(type(dict))  # <class 'type'>

class A: pass
print(type(A))   # 输出 <class 'type'>
print(type(A()))  # 输出 <class '__main__.A'>

除了type,还有:

  • isinstance:判断一个对象是否是一个已知的类型
  • issubclass:判断一个类是不是另一个类的子类

内存自身id

id() 函数返回对象的唯一标识符,这通常是对象在内存中的地址。n

# 示例:使用 id() 获取对象的标识符
a = 100
print(id(a))  # 输出一个整数,表示对象 a 的标识符

属性方法自省

dir

dir() 函数用于返回对象的属性和方法列表。如果没有参数,则返回当前作用域(模块)的名称列表。

# 示例:使用 dir() 列出对象的属性和方法
class Sample:
    def __init__(self):
        self.name = "Sample"

    def greet(self):
        return "Hello"

obj = Sample()
print(dir(obj))  # 输出包含 ['name', 'greet', '__class__', '__delattr__', '__dict__', ...] 的列表
getattr, setattr, hasattr

这些getattr(), setattr(), 和 hasattr()函数用于动态地获取、设置和检查对象的属性。

class Person:
    def __init__(self, name):
        self.name = name

p = Person("Matt")
print(getattr(p, "name"))  # 输出 'Matt'
setattr(p, "name", "Math")
print(p.name)              # 输出 'Math'
print(hasattr(p, "name"))  # 输出 True
inspect模块

inspect 模块提供了更强大的自省功能,允许检查活跃的帧、获取模块信息、查找类的成员等。

import inspect

# 示例:使用 inspect 模块获取类的信息
class Animal:
    def __init__(self, species):
        self.species = species

def feed():
    pass

print(inspect.getmembers(Animal))  # 输出 Animal 类的成员
print(inspect.isclass(Animal))     # 输出 True
print(inspect.isfunction(feed))    # 输出 True
vars

vars() 函数返回对象的 __dict__ 属性,即对象的属性字典。如果没有参数,则返回当前局部变量的字典。

# 示例:使用 vars() 获取对象的属性字典
class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model

car = Car("Toyota", "Corolla")
print(vars(car))  # 输出 {'make': 'Toyota', 'model': 'Corolla'}
callable

callable() 函数用于检查对象是否可调用(即是否可以像函数一样使用)。

# 示例:使用 callable() 检查对象是否可调用
def say_hello():
    print("Hello")

print(callable(say_hello))  # 输出 True
print(callable(42))         # 输出 False
dict

__dict__ 是一个包含对象的可写属性的字典。用于获取或设置对象的属性。

# 使用 __dict__ 获取对象的属性
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

user = User("小明", 20)
print(user.__dict__)  # 输出 {'name': '小明', 'age': 20}
annotations

__annotations__ 属性存储变量的类型注解,是一个字典。

def func(name: str, age: int) -> str:
    return f"{name} is {age} years old."

print(func.__annotations__)  # 输出 {'name': <class 'str'>, 'age': <class 'int'>, 'return': <class 'str'>}

综合示例

为了更好地理解 Python 自省的综合应用,我们可以创建一个学生类并展示如何使用这些工具来动态检查和操作类实例。

class Students:
    def __init__(self, std_id, name, grade):
        self.std_id = std_id
        self.name = name
        self.grade = grade

    def promote(self, new_grade):
        """升班"""
        self.grade = new_grade

# 创建 Students 对象
std = Students(1, "小明", "fifth")

# 获取对象的类型
print(type(std))  # <class '__main__.Students'>

# 获取对象的唯一标识符
print(id(std))  # 一个整数,表示对象的唯一标识符

# 列出对象的属性和方法
print(dir(std))  # 列出 Students 对象的所有属性和方法
# 如:['__class__', '__delattr__', ..., 'grade', 'name', 'promote', 'std_id']

# 动态获取和设置对象的属性
print(getattr(std, "name"))  # '小明'
setattr(std, "grade", "sixth")
print(std.grade)  # 'sixth'

# 检查对象是否具有特定属性
print(hasattr(std, "std_id"))  # True

# 使用 inspect 获取类的成员信息
import inspect
print(inspect.getmembers(Students))  # 获取 Students 类的成员信息
# 如:[('__class__', <class 'type'>), ...]

# 使用 vars() 获取对象的属性字典
print(vars(std))  # {'std_id': 1, 'name': '小明', 'grade': 'sixth'}

# 检查对象是否可调用
print(callable(std.promote))  # True

# 使用 __dict__ 获取对象的属性
print(std.__dict__)  # {'std_id': 1, 'name': '小明', 'position': 'sixth'}

作用

  • 自省用于调试和日志,可以在运行时获取对象的详细信息,帮助开发者快速定位问题。
  • 动态属性访问和设置:使用 getattr(), setattr(), hasattr() 可以动态访问和设置对象的属性,这在处理动态数据结构时非常有用。
  • 自动化测试:自省可以自动生成测试用例或在运行时检查对象的状态,以确保测试覆盖率。 比如:生成对象的方法列表用于测试
  • 在ORM(对象关系映射)中,自省用于将数据库表映射到 Python 对象,自动生成属性和方法。
# 简单 ORM 映射
class User:
    def __init__(self, id, name, email):
        self.id = id
        self.name = name
        self.email = email

def serialize(obj):
    return {attr: getattr(obj, attr) for attr in vars(obj)}

user = User(1, "Jeff", "jeff@example.com")
print(serialize(user))

# Output
# {'id': 1, 'name': 'Jeff', 'email': 'jeff@example.com'}
  • 序列化和反序列化:自省用于序列化对象为 JSON 或其他格式,并在需要时重新构建对象。
# 对象序列化为 JSON
import json

class Product:
    def __init__(self, id, name, price):
        self.id = id
        self.name = name
        self.price = price

def serialize_to_json(obj):
    return json.dumps(vars(obj))

product = Product(1, "电脑", 10000)
json_data = serialize_to_json(product)
print(json_data)

# Output
# {"id": 1, "name": "\u7535\u8111", "price": 10000}
  • 动态代码生成

总结

一门语言想要强大,那它也必须做到自省,全面了解自己。Python作为一门强大编程语言,那自省机制是必不可少的。

在日常开发中,掌握和应用这些自省工具将极大地帮助我们迅速定位并解决复杂的问题,并提高代码的可维护性和可扩展性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值