DAY21 反射(hasattr,getattr,setattr,delattr)

Python反射机制详解
本文详细介绍了Python中的反射机制,包括getattr(), hasattr(), setattr(), delattr()等四个核心函数的使用方法,并通过实例演示了如何利用这些函数进行动态操作。此外,文章还探讨了如何运用反射机制来操作模块和当前文件。

反射

(1)反射的定义:

  反射就是通过字符串来操作python代码中的对象的属性和方法。

(2)为什么要用反射?三个场景:

  1.用户输入input

    从用户输入的字符串中,想转换为变量的名字。

  2.文件读取

    从文件中读出的字符串,想转换为变量的名字。

  3.网络


getattr()

  先看看getattr()的源码的解释:

def hasattr(*args, **kwargs): # real signature unknown
    """
    Return whether the object has an attribute with the given name.
    
    This is done by calling getattr(obj, name) and catching AttributeError.
    """
    pass
getattr()源码解释

  具体使用:

  (1)getattr(obj,属性名)----> 传入字符串类型的属性名,返回属性的值,相当于执行了“obj.属性名”

  (2)getattr(obj,方法名)----> 传入字符串类型的方法名,返回对应方法的内存地址。

  谨记:如果第二个参数不存在的话,就会报错。

class A:
    name = 'he'
    age = 23
print(A.name)    #he
print(A.age)       #23

#使用反射的形式,操作类的属性
print(getattr(A, 'name'))
>>>
he
#使用反射操作类中的方法
class A:
    number = 1
    def func(self):
        print('in the func')
a = A()
ret = getattr(a,'func')      #得到了func方法的内存地址
ret()                              #调用func()方法

hasattr()

def hasattr(*args, **kwargs): # real signature unknown
    """
    Return whether the object has an attribute with the given name.
    
    This is done by calling getattr(obj, name) and catching AttributeError.
    """
    pass
hasattr的源码解释

 

  具体使用:

  hasattr(obj,字符串类型的属性名/方法名)--->判断对象中是否拥有指定属性/方法,返回True/False。

  谨记:所以hasattr经常和getattr一起使用,先用hasattr判断,再使用getattr取值。

#例子1:通过hasattr判断,再用getattr来取值。
class A:
    name = 'he'
    age = 23

inp = input('>>>:')
if hasattr(A,inp):
    print(getattr(A,inp))
else:
    print('A类中没有对应的属性')

>>>:name
he
>>>:sex
A类中没有对应的属性


#例子2
class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show(self):
        for key in self.__dict__:                 #__dict__查看对象的所有属性
            print(key,self.__dict__[key])         # key self.__dict__[key]

s = Student('he',23)
# s.show()

if hasattr(s,'show'):
    func = getattr(s,'show')        #返回方法的内存地址,赋值给func()
    func()
>>>
name he
age 23

setattr()

 

def setattr(x, y, v): # real signature unknown; restored from __doc__
    """
    Sets the named attribute on the given object to the specified value.
    
    setattr(x, 'y', v) is equivalent to ``x.y = v''
    """
    pass
setattr的源码解释

 

  具体使用:

  setattr(obj,'name',value) ---->通过反射的方式为一个对象设置属性(增改操作),相当于obj.name=value

#正常情况下,想给对象设置一个值。
class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show(self):
        for key in self.__dict__:      #__dict__查看对象的所有属性
            print(key,self.__dict__[key]) # key self.__dict__[key]

s = Student('he',23)
s.sex = 'male'
print(s.sex)
>>>
male

#除了上面的方式之外,还有一种方式为对象设置属性,通过反射的形式.
setattr(s,'sex','male')
print(s.__dict__)
print(s.sex)
>>>
{'name': 'he', 'age': 23, 'sex': 'male'}

  除了给对象绑定属性,还给对象绑定一个函数。

#创建一个函数,通过setattr给对象绑上这个函数
class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show(self):
        for key in self.__dict__:         #__dict__查看对象的所有属性
            print(key,self.__dict__[key]) # key self.__dict__[key]

s = Student('he',23)
def func1(a,b):
    print(a,b)
setattr(s,'func',func1)       #把普通函数当做函数添加到对象空间中
s.func(1,2)
print(s.__dict__)
>>>:
1 2
{'name': 'he', 'age': 23, 'func': <function func1 at 0x000001F16D252F28>}

delattr()

  delattr(obj,'name'):通过反射的方式,删除对象中的属性(删除操作)

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show(self):
        for key in self.__dict__:      #__dict__查看对象的所有属性
            print(key,self.__dict__[key]) # key self.__dict__[key]

s = Student('he',23)
#正常方法
del s.age
print(s.__dict__)

#通过delattr反射的方式
delattr(s,'age')
print(s.__dict__)

  总结:

  (1)hasattr():判断一个对象中是否能够调用一个名字,返回True/False

  (2)getattr():返回一个对象中的名字的值

  (3)setattr():为一个对象设置属性(增加/修改操作)

  (4)delattr():删除一个对象的某个属性(删除操作)


 

通过反射来操作模块

  通过上面学习的反射的四种方法,我们知道了如果通过反射来操作类中的属性/方法,但是除了"类名.属性名/方法名","对象名.属性名/方法名"之外,我们还接触过“模块名.函数名()”,那么能否通过反射来操作模块呢?答案是肯定的。

  在python中,一切皆对象,当导入一个模块时,模块其实就可以看成一个对象。

  getattr(模块,'属性名/方法名')

import sys
print(getattr(sys, 'path'))       
>>>
C:\Python36\python.exe E:/python_training_s1/day21/day21_training.py
['E:\\python_training_s1\\day21', 'E:\\python_training_s1', 'C:\\Python36\\python36.zip', 
'C:\\Python36\\DLLs', 'C:\\Python36\\lib', 'C:\\Python36',
'C:\\Users\\hesihao\\AppData\\Roaming\\Python\\Python36\\site-packages',
'C:\\Python36\\lib\\site-packages',
'D:\\pycharm\\PyCharm 2018.1.4\\helpers\\pycharm_matplotlib_backend']

通过反射来操作当前文件

  既然反射能够操作模块,那么当前文件其实也是一个模块,通过sys.modules可以看出,当前文件就是sys.modules['__main__']

# 方式一:sys.modules[__main__]
import sys
name = 'he'
def foo():
    print('这是本模块的函数foo')

print(getattr(sys.modules['__main__'], 'name'))
getattr(sys.modules['__main__'], 'foo')()
>>>
he
这是本模块的函数foo

  通过sys.modules['__main__']好像完成了要求,但是,仔细想一下,使用__main__表示当前文件,假如在另外一个py文件中把当前文件导入,此时__main__便指向的是另外一个py文件,使用sys.modules['__main__']这种方式显然是不妥的,那么要怎么解决?

  使用sys.modules[__name__]就能完美解决,因为__name__就是'__main__'。

#通过sys.modules[__name__]反射当前模块
import sys name = 'he' def foo(): print('这是本模块的函数foo') getattr(sys.modules[__name__],'foo')() >>> 这是本模块的函数foo

  总结:

  sys.modules['__main__'] : __main__会随着文件的不同而不同,存在安全隐患。

  sys.modules[__name__]:__name__不管在哪里导入这个模块,都代表这个文件。

如何反射来操作当前模块中的类

import sys
class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show(self):
        for key in self.__dict__:      #__dict__查看对象的所有属性
            print(key,self.__dict__[key]) # key self.__dict__[key]


main = sys.modules[__name__]
cls = getattr(main,'Student')
he = cls('小何',23)

  

 

转载于:https://www.cnblogs.com/hebbhao/p/9594263.html

<think>嗯,用户想了解Python中的callable和getattrsetattrdelattrhasattr这些函数的关系和用法。首先,我需要回忆这些函数各自的作用,然后看看它们之间有什么联系。先分开来看,hasattr用于检查对象是否有某个属性,setattr用来设置属性值,getattr获取属性值,delattr删除属性。而callable则是判断一个对象是否可以被调用,比如函数或类。这些函数都属于Python的内置函数,用于动态处理对象的属性。 接下来,需要理清它们之间的关系。例如,当使用getattr获取一个属性时,如果该属性是一个方法(即可调用的),那么可以用callable来验证。或者,在动态调用方法前,先用hasattr检查是否存在,再用callable确认是否可执行。用户可能在实际开发中遇到动态处理对象属性的情况,比如根据输入的字符串调用不同的方法,这时候结合使用这些函数会很方便。比如,检查对象是否有某个方法(hasattr),确认方法存在后再判断是否可调用(callable),最后用getattr获取并执行。 还需要注意异常处理,比如使用delattr删除属性时,如果属性不存在会引发AttributeError,所以可能需要结合try-except块或者先用hasattr检查。此外,在动态设置属性时,setattr可以直接赋值,但如果属性名是变量,这会很有用。另外,引用中提到的一些情况,比如在__getattr__方法中避免无限循环,可能需要通过直接操作__dict__来实现。这点虽然和用户的问题没有直接关联,但如果在动态属性管理时涉及到这些魔术方法,需要注意。用户的问题可能还涉及到如何组合使用这些函数来实现动态行为。例如,在插件系统中动态加载模块的方法,或者根据配置调用不同的函数。这时候,hasattrgetattr配合使用,再加上callable检查,可以确保调用的有效性。 需要举例说明每个函数的用法,以及它们如何协同工作。比如,一个对象可能有多个方法,根据用户输入动态选择执行哪个方法。这时候,先用hasattr检查是否存在,再用getattr获取,callable判断是否可调用,最后调用。 另外,callable不仅可以用于方法,还可以用于其他可调用对象,比如类、lambda函数等。所以,在动态获取属性后,用callable确认是否可调用,可以增加代码的健壮性。可能还需要提到这些函数与__getattr__、__setattr__等魔术方法的关系,比如当使用getattr时,会触发对象的__getattr__方法,如果存在的话。但用户的问题可能更关注于内置函数的使用,而不是魔术方法的覆盖。 最后,总结它们的关系:hasattr用于检查属性是否存在,getattr获取属性值,setattr设置,delattr删除,而callable则判断获取的属性是否可调用。这些函数共同支持了Python中动态属性管理的功能。</think>### Python动态属性管理与可调用对象检测 在Python中,`callable()`与`hasattr()`/`getattr()`/`setattr()`/`delattr()`共同构成动态属性管理的核心工具组,其关系与用法可通过以下结构化分析理解: --- #### 一、基础功能对比 1. **属性检测** `hasattr(obj, 'attr')`:判断对象是否包含指定属性(包括继承属性) ```python class Data: def __init__(self): self.value = 42 obj = Data() print(hasattr(obj, 'value')) # True ``` 2. **属性操作** - `getattr(obj, 'attr', default)`:获取属性值,支持默认值[^1] - `setattr(obj, 'attr', value)`:动态设置/修改属性[^1] - `delattr(obj, 'attr')`:删除属性(需配合异常处理)[^3] 3. **可调用性验证** `callable(obj.attr)`:判断属性是否为函数/方法/类等可调用对象 --- #### 二、组合应用场景 **案例:动态方法调用** ```python class Calculator: def add(self, a, b): return a + b calc = Calculator() method_name = 'add' if hasattr(calc, method_name): # 1.检测方法是否存在 func = getattr(calc, method_name) # 2.获取方法引用 if callable(func): # 3.验证可调用性 print(func(3, 5)) # 输出8 ``` **关键流程**: `存在性检测 → 属性获取 → 可调用性验证 → 执行调用` --- #### 三、特殊注意事项 1. **`delattr()`的异常处理** 删除不存在的属性会触发`AttributeError`,需配合`try-except`或前置`hasattr()`检查[^3]: ```python try: delattr(obj, 'non_existent_attr') except AttributeError as e: print(f"删除失败: {e}") ``` 2. **动态属性与`__dict__`的关系** 直接操作`obj.__dict__`可避免触发`__getattr__`/`__setattr__`的递归调用问题[^4] 3. **方法链式调用** `getattr()`可直接返回方法并立即调用: ```python getattr(calc, 'add')(3, 5) # 等效于calc.add(3,5) ``` --- #### 四、核心区别总结 | 函数 | 作用域 | 返回值类型 | 典型应用场景 | |---------------|----------------|-----------------|--------------------------| | `hasattr()` | 属性存在性检测 | 布尔值 | 动态功能开关控制 | | `getattr()` | 属性值获取 | 任意类型 | 插件系统/反射编程 | | `setattr()` | 属性赋值 | None | 运行时配置注入 | | `delattr()` | 属性删除 | None | 资源释放/状态重置 | | `callable()` | 可调用性验证 | 布尔值 | 安全执行回调函数 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值