详细讲述python自省函数getattr的用法

这两天看了公司的老代码,发现有大量的在用getattr….  虽然在不得已的时候,也会考虑用getattr,只是没这么频繁而已….    

这边的getattr主要是用在函数调用上,比如一个简单的rpc服务,里面注册了N个函数,这时候,客户端是知道自己需要调用哪个函数的,他给我传递了一个名字叫getName函数名,那么我用getattr直接调用就OK了….

关于python内建函数getattr的用法,文章出处  http://xiaorui.cc/?p=1798

getattr是python里的一个内建函数,在python的官方文档中:getattr()的解释:

getattr(object, name[, default])

Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, ‘foobar’) is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.

getattr()这个方法最主要的作用是实现反射机制。也就是说可以通过字符串获取方法实例。这样,你就可以把一个类可能要调用的方法放在配置文件里,在需要的时候动态加载。

python里面跟getattr相关的有hasattr,setattr,delattr  ,那么我们通过下面的例子,来详细的说说他们的用法。 

Python

#!/usr/bin/python
class Xiaorui:

     def __init__(self):

        self.name = ‘fengyun’

    def setName(self,name):

        self.name = name

    def getName(self):

        return self.name

    def greet(self):

        print “Hello,i’m %s”%self.name  

foo = Xiaorui()

一. hasattr(object,name)

bool       判断object中是否具有name属性,例如:

foo = Xiaorui()

hasattr(foo,’setName’) #判断setName是否存在,存在则返回True。

二. getattr(object,name,default)

如果存在name属性(方法)则返回name的值(方法地址)否则返回default值。

getattr(foo,’name’,’NA’) #存在name属性,所以返回其value

‘fengyun’

getattr(foo,’age’,’NA’)

‘NA’

一会发现,他其实跟直接object.name 用法一样。 

三. setattr(object,name,default)

setattr(foo,’age’,’18’) #

字符串可能会列出一个现有的属性(或一个新的属性)。这个函数将值赋给属性的

.类似foo.age = 18

getattr(foo,’age’,’not find’)

’18’ 

setattr(foo,’work’,’student’) #

可以用setattr方法,把foo的work变量,设置为student

getattr(foo,’work’,’not find’)

‘student’

四. delattr(object,’name’)

delattr(foo,’name’)#删除属性name,原值为‘fengyun’

getattr(foo,’name’,’not find’)

‘not find’

今重点是getattr的用法, 我也不多说了,就简单写个例子,说明下,我一般是怎么用getattr的。 

Python

#xiaorui.cc
import test

import multiprocessing

def run(func,*args):
#    print getattr(test, "hello")("hello", "world")
    print getattr(test, func)(*args)

pool = multiprocessing.Pool(processes=4)
for i in xrange(10):
    pool.apply_async(run, ('hello','hello','world' ))
    pool.apply_async(run, ('test_sleep','hello','world' ))
pool.close()
pool.join()
print "END from xiaorui.cc"

文件名是,  test.py

Python

import time

def hello(str1, str2):
    print 'hello'
    return [str1, str2]

def test_sleep(str1, str2):
    print 'test_sleep'
    time.sleep(3)
    return [str1, str2]
这个时候,我们可以定义一个字符串,然后用getattr去执行,这样调用效果有些类似python的celery那种用globals的用法。 我传递一个函数的名字,当然是字符串,我可以用multiprocessing多进程调用这个方法。
<think>好的,我现在要介绍Python自省和反射。首先,我需要明确这两个概念的定义,确保自己理解正确。自省(Introspection)是指程序在运行时能够查看和访问对象的属性和方法的能力。而反射(Reflection)则更进一步,允许程序在运行时动态地修改对象的属性和方法,甚至创建新的对象实例。用户可能需要了解它们的区别以及如何在Python中使用这些特性。 接下来,我应该分步骤组织内容。先从自省开始,举例说明Python中常用的自省函数,比如type(), dir(), id(), hasattr(), getattr()等。需要说明每个函数的作用和使用场景,例如type()用于获取对象类型,dir()列出对象的属性和方法。然后可以提到inspect模块,它提供了更高级的自省功能,比如检查函数参数或源代码。 然后是反射部分,需要强调反射的动态特性。例如,通过setattr()动态设置属性,或者使用getattr()获取属性并调用方法。这里可以举一个实际的例子,比如根据字符串名称调用对象的方法,展示反射的灵活性。此外,可以提到__import__函数动态导入模块,这也是反射的一种应用。 需要注意的是,用户可能对这两个概念容易混淆,因此要明确区分自省和反射的不同。自省主要是查询信息,而反射则是修改或操作。同时,要提醒用户在使用反射时注意安全性和可维护性,因为动态修改可能会带来意想不到的问题。 另外,可以补充一些实际应用场景,比如在框架开发中,反射常用于根据配置动态加载类或方法;自省则常用于调试或日志记录,查看对象状态。还可以提到装饰器、元类等高级特性如何与自省和反射结合使用,但可能不需要深入细节,保持回答的简洁性。 最后,总结两者的重要性和在Python中的实现方式,帮助用户形成整体理解。检查是否有遗漏的关键点,比如特殊属性__dict__的使用,或者如何处理异常情况(如属性不存在时的处理)。确保示例代码正确,语法无误,并符合用户的可读性需求。</think>### Python 自省(Introspection)与反射(Reflection)详解 --- #### **1. 自省(Introspection)** **定义**:程序在运行时**查看和访问对象信息**的能力,例如对象的类型、属性、方法等。 **核心函数与工具**: - **`type(obj)`**:获取对象类型 ```python print(type(42)) # <class 'int'> ``` - **`dir(obj)`**:列出对象所有属性和方法 ```python print(dir("hello")) # 显示字符串的所有方法,如 'upper', 'split' 等 ``` - **`id(obj)`**:获取对象内存地址 - **`hasattr(obj, 'attr')`**:检查对象是否有某个属性或方法 ```python hasattr([1,2,3], 'append') # True ``` - **`getattr(obj, 'attr')`**:获取属性的值(或方法引用) ```python method = getattr("hello", "upper") print(method()) # 输出 "HELLO" ``` - **`inspect` 模块**:更强大的自省工具,例如检查函数参数、源码等 ```python import inspect print(inspect.getfullargspec(print)) # 查看print函数的参数 ``` --- #### **2. 反射(Reflection)** **定义**:程序在运行时**动态修改或创建对象**的能力,例如通过字符串操作属性或方法。 **核心操作**: - **`setattr(obj, 'attr', value)`**:动态设置属性 ```python class MyClass: pass obj = MyClass() setattr(obj, 'new_attr', 100) print(obj.new_attr) # 输出 100 ``` - **`delattr(obj, 'attr')`**:删除属性 - **动态调用方法**:通过字符串名称调用方法 ```python class Calculator: def add(self, a, b): return a + b calc = Calculator() method = getattr(calc, 'add') print(method(2, 3)) # 输出 5 ``` - **动态导入模块**:通过字符串导入模块 ```python module_name = "math" math_module = __import__(module_name) print(math_module.sqrt(4)) # 输出 2.0 ``` --- #### **3. 自省 vs 反射** | **特性** | **自省** | **反射** | |----------------|-----------------------------|-----------------------------| | **核心功能** | 查看对象信息 | 动态修改/创建对象 | | **典型函数** | `type()`, `dir()`, `hasattr()` | `setattr()`, `getattr()` | | **应用场景** | 调试、日志、文档生成 | 插件系统、ORM框架、动态配置 | --- #### **4. 应用场景** - **框架开发**:Django 或 Flask 通过反射动态加载路由和视图函数。 - **动态配置**:根据配置文件字符串调用对应方法。 - **调试工具**:通过自省检查对象状态。 - **装饰器与元类**:结合自省实现动态行为控制。 --- #### **5. 注意事项** 1. **安全性**:反射可能引入安全风险(如通过用户输入直接调用方法)。 2. **可读性**:过度使用反射会降低代码可维护性。 3. **异常处理**:使用 `try...except` 处理属性不存在的情况。 --- #### **示例:动态调用方法** ```python class User: def login(self): print("登录成功") def logout(self): print("退出登录") user = User() action = input("请输入操作(login/logout): ") if hasattr(user, action): method = getattr(user, action) method() # 根据输入动态调用方法 else: print("无效操作") ``` --- 通过自省和反射,Python 能够实现高度灵活的编程模式,但也需谨慎使用以保持代码清晰和安全。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值