【python3学习笔记】 ---- python之反射机制详解、getattr、hasattr、setattr、delattr函数详解

        在程序开发中,常常会遇到这样的需求:在执行对象中的某个方法,或者在调用对象的某个变量,但是由于一些原因,我们无法确定或者并不知道该方法或者变量是否存在,这时我们需要一个特殊的方法或者机制来访问或操作该未知的方法或变量,这种机制就被称之为反射

    · 反射机制:反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块中寻找指定函数,对其进行操作。也就是利用字符串的形式去对象(模块)中操作(查找or获取or删除or添加)成员,一种基于字符串的事件驱动。

下面先介绍发射机制中的常用的几个函数:

· getattr()  函数用于返回一个对象的属性值

获取对象object的属性或者方法,存在则返回其属性,不存在则返回默认值,默认值可选。

注意:如果获取的是方法,存在则返回对象中方法的内存地址,若想运行则需通过"()"方法.

# getattr 语法
getattr(object,name[,default])

#参数
# · object -- 对象
# · name   -- 字符串,对象属性
# · default-- 默认返回值,如果不提供该参数,在没有对应属性时,将触发AttrbuteError.

# 返回值 :返回对象属性值 
class test():
    name="david"
    def run(self):
        return "Hello David"
t=test()        # t 为一个test对象
getattr(t, "name") #获取name属性
getattr(t, "run")  #获取run方法,存在就打印出方法的内存地址。
<bound method test.run of <__main__.test instance at 0x0269C878>>
getattr(t, "run")()  #获取run方法,后面加括号可以将这个方法运行。
'Hello David'
getattr(t, "david")  #获取一个不存在的属性。
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: test instance has no attribute 'david'
getattr(t, "david","18")  #若属性不存在,返回一个默认值。
'18'

· hasattr() 函数用于判断对象是够包含对应的属性

判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。

需要注意的是name是一个字符串字面值或字符串类型变量。

# hasattr 语法
hasattr(object,name)

#参数
# · object -- 对象
# · name   -- 字符串,属性名

# 返回值 :如果对象有该属性返回 True,否则返回 False。
t=test()           # test 还是上面的那个
hasattr(t, "name") #判断对象有name属性
True
hasattr(t, "run")  #判断对象有run方法
True

· setattr() 函数对应函数getattr(),用于设置属性值,若属性不存在,则先创建在赋值。

给对象的属性赋值,若属性不存在,先创建再赋值。

# setattr 语法
setattr(object, name, value)

#参数
# · object -- 对象
# · name   -- 字符串,属性名
# · value  -- 属性值。

# 返回值 :无
>>> t=test()
>>> hasattr(t, "hdw")   #判断属性是否存在
False
>>> setattr(t, "hdw", "18")   #为属相赋值,并没有返回值
>>> hasattr(t, "hdw")    #属性存在了
True

· delattr() 函数用来删除指定对象的指定名称的属性,和setattr函数作用相反,属性必须存在,否则发出AttributeError。

delattr(object, name)
  This is a relative of setattr(). The arguments are an object and a string. The string must be the name of one of the object’s attributes. The function deletes the named attribute, provided the object allows it. For example, delattr(x, 'foobar') is equivalent to del x.foobar.
#定义类A
class A:
    def __init__(self,name):
        self.name = name
    def sayHello(self):
        print('hello',self.name)
A a;    # a是一个A对象
#测试属性和方法
a.name
'小麦'
a.sayHello()
hello 小麦

#删除属性
>>> delattr(a,'name')
>>> a.name
Traceback (most recent call last):
  File "<pyshell#47>", line 1, in <module>
    a.name
AttributeError: 'A' object has no attribute 'name'
>>> a.name #属性name已经删掉,不存在
Traceback (most recent call last):
  File "<pyshell#47>", line 1, in <module>
    a.name
AttributeError: 'A' object has no attribute 'name'

>>> delattr(a,'name') #再删除会报错
Traceback (most recent call last):
  File "<pyshell#48>", line 1, in <module>
    delattr(a,'name')
AttributeError: name
>>> a.sayHello
<bound method A.sayHello of <__main__.A object at 0x03F014B0>>
>>> delattr(a,'sayHello') #不能用于删除方法
Traceback (most recent call last):
  File "<pyshell#50>", line 1, in <module>
    delattr(a,'sayHello')
AttributeError: sayHello
>>>

· eval() 函数用来执行一个字符串表达式,并返回表达式的值。

# 语法
eval(expression[, globals[, locals]])

#参数
# expression -- 表达式。
# globals 	 -- 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
# locals	 -- 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。

# 返回值:表达式计算结果。
>>>x = 7
>>> eval( '3 * x' )
21
>>> eval('pow(2,2)')
4

反射机制的用法:    

imp = input(“请输入你想导入的模块名:”)
CC = __import__(imp) 這种方式就是通过输入字符串导入你所想导入的模块 
CC.f1()  # 执行模块中的f1方法

上面实现了动态输入模块名,从而可以执行里面的函数,但是有一个缺点,就是执行的函数被固定了。那如何动态输入函数名并且来执行呢?这就的通过反射机制。

#dynamic.py
imp = input("请输入模块:")
dd = __import__(imp)    # 等价于import imp
inp_func = input("请输入要执行的函数:")

f = getattr(dd,inp_func,None)    #作用:从导入模块中找到你需要调用的函数inp_func,然后返回一个该函数的引用.没有找到就烦会None

f() # 执行该函数
上面实现了,动态导入一个模块,并且动态输入函数名然后执行相应功能。

当然,上面还存在一点点小问题:那就是我的模块名有可能不是在本级目录中存放着。有可能是如下图存放方式:

  

那么就得用下面的方式了。

dd = __import__("lib.text.commons")  #这样仅仅导入了lib模块
dd = __import__("lib.text.commons",fromlist = True)  #改用这种方式就能导入成功
# 等价于import config
inp_func = input("请输入要执行的函数:")
f = getattr(dd,inp_func)
f()

平常可能需要用到上面的四个函数。

r = hasattr(commons,xxx)             # 判断某个函数或者变量是否存在
print(r)  

setattr(commons,'age',18)            # 给commons模块增加一个全局变量age = 18,创建成功返回none

setattr(config,'age',lambda  a:a+1)  # 给模块添加一个函数

delattr(commons,'age')               # 删除模块中某个变量或者函数
注:getattr,hasattr,setattr,delattr对模块的修改都在内存中进行,并不会影响文件中真实内容。

反射机制常常都是使用在web框架上,比如你浏览某个网页,你点网页上的文字或则图片,则会跳转或者说生成新的页面,这是怎么实现的呢?就是采用反射机制实现的,当你点击某个东西是不是就对应不同的url,而url是字符串的形式,穿进去,就可以通过那几个函数找到对应的实现方法。

下面来一个基于反射机制模拟的web框架路由

需求:输入www.xxx.com/commons/fun,则返回fun的结果,不存在则返回404

# 动态导入模块,并执行其中函数
url = input("url: ")

target_module, target_func = url.split('/')
m = __import__('lib.'+target_module, fromlist=True)

inp = url.split("/")[-1]  # 分割url,并取出url最后一个字符串
if hasattr(m,target_func):  # 判断在commons模块中是否存在inp这个字符串
    target_func = getattr(m,target_func)  # 获取inp的引用
    target_func()  # 执行
else:
    print("404")





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值