反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
反射机制就是在运行时,动态的确定对象的类型,并可以通过字符串调用对象属性、方法、导入模块,是一种基于字符串的事件驱动。
解释型语言:程序不需要编译,程序在运行时才翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。相对于编译型语言存在的,源代码不是直接翻译成机器语言,而是先翻译成中间代码,再由解释器对中间代码进行解释运行。比如Python/JavaScript / Perl /Shell等都是解释型语言。
python是一门解释型语言,因此对于反射机制支持很好。在python中支持反射机制的函数有getattr()、setattr()、delattr()、exec()、eval()、__import__,这些函数都可以执行字符串。
eval
计算指定表达式的值。它只能执行单个表达式,而不能是复杂的代码逻辑。而且不能是赋值表达式。 单个表达式
a = "12 + 43" b = eval(a) print(b)#55
exec
执行复杂表达式,返回值永远都是None
b = exec("aa = 21") print(b) # None,exec返回值为None print(aa) # 21,exec执行了赋值语句,并定义了aa变量
执行复杂语句
a = '''ret = [] for i in range(10): ret.append(i)''' exec(a) print(ret) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
导入模块
config.py
KEYWORD = 123
# 导入模块 exec("import config") print(config.KEYWORD) # 动态创建类 class Base: def __init__(self): print("Base") a = "Base" exec(a+"()")
导入模块这个功能就非常屌了,这样我们就可以动态的创建各种模块类。
eval()函数和exec()函数的区别: eval()函数只能计算单个表达式的值,而exec()函数可以动态运行代码段。 eval()函数可以有返回值,而exec()函数返回值永远为None。
再看一下下面的例子:
class Base: def __init__(self): print("Base") def test(self): print("test") return "Base::test" a = "Base" b = eval(a+"()") # b = eval("b.test()") b = exec("b.test()") print(b)
输出: test Base::test 如果不需要获取返回值,那么可以使用exec,exec("a.test()")
,输出:test
虽然我们可以使用eval和exec来执行以上代码,但是这种方式有一个缺陷,假如这个属性是不存在的,那么这种调用就会报错。那么做好的方式是什么呢?先判断属性是否存在,如果存在就调用,不存在就不调用,python为我们提供了一套方法:hasattr、getattr、setattr、delattr
一、getattr
对象获取
# coding:utf-8 class Manager: role = "管理员" def __init__(self,name,sex,phone,mail): self.name = name self.sex = sex self.phone = phone self.mail = mail def createClass(self): print("create class") def createTeacher(self): print("createTeacher") def createStu(self): print("createStu") manager = Manager("safly","男",123456,123456) print("---对象获取对象方法-----") f = getattr(manager,"createClass") f() print("---对象获取对象属性-----") name = getattr(manager,"name") print(name) print("---对象获取类属性-----") role = getattr(manager,"role") print(role) print("---对象获取类属性(可以设置默认值)-----") import logging if hasattr(manager,"role1"): role = getattr(manager,"role1","roleDefault") print(role) else: logging.warn("没有role属性") role = getattr(manager, "role1", "roleDefault") print(role)
运行结果:
---对象获取对象方法----- create class ---对象获取对象属性----- safly ---对象获取类属性----- 管理员 ---对象获取类属性(可以设置默认值)----- WARNING:root:没有role属性 roleDefault
类获取
#coding=utf-8 class Manager: role = "管理员" def createClass(self): print("create class") def createStu(self): print("createStu") m = Manager() f = getattr(Manager,"createClass") f(Manager()) f = getattr(Manager,"createClass") f(m) role = getattr(Manager,"createStu") role(m) #对象获取类属性 role = getattr(Manager,"role") print(role)
Traceback (most recent call last):
File "E:/program/ljt_test/test/test2.py", line 13, in <module>
f(Manager)#参数需要是类实例,忘了写括号。
TypeError: unbound method createClass() must be called with Manager instance as first argument (got classobj instance instead)
运行输出:
create class create class createStu 管理员
二、setattr
设置类属性、方法
class Manager: role = "管理员" def __init__(self,name,sex,phone,mail): self.name = name self.sex = sex self.phone = phone self.mail = mail def createClass(self): print("create class") manager = Manager("safly","男",123456,123456) print("----设置类属性------") setattr(Manager,"country","china") print(Manager.country) print("----删除类属性------") delattr(Manager,"country") # #删除报错 # print(Manager.country) print("----设置类方法------") @staticmethod def Method(cls,parm): print u"我是被绑定的class之外的方法parm--",parm setattr(Manager,"Method",Method) Manager.Method(Manager,1)
运行结果:
----设置类属性------ china ----删除类属性------ ----设置类方法------ 我是被绑定的class之外的方法parm-- 1
设置对象属性、方法
#coding=utf-8 class Manager: role = "管理员" def __init__(self,name,sex,phone,mail): self.name = name self.sex = sex self.phone = phone self.mail = mail def createClass(self): print("create class") def createTeacher(self): print("createTeacher") def createStu(self): print("createStu") manager = Manager("safly","男",123456,123456) print("----设置对象属性------") setattr(manager,"age",20) print(manager.age) print("----删除对象属性------") delattr(manager,"age") # 'Manager' object has no attribute 'age' # print(manager.age) print("---对象不能删除类属性---") setattr(Manager,"country","china") print(Manager.country) # delattr(manager,"country") # print(Manager.country) print("----设置对象方法------") def create_course(self): print('创建了一个课程') setattr(manager,'create_course',create_course) manager.create_course(manager) def create_grade(): print('创建了一个班级') setattr(manager,'create_grade',create_grade) manager.create_grade() print manager.__dict__ exit(0)
运行输出结果:
----设置对象属性------ 20 ----删除对象属性------ ---对象不能删除类属性--- china ----设置对象方法------ 创建了一个课程 创建了一个班级 {'name': 'safly', 'create_course': <function create_course at 0x022F6D30>, 'create_grade': <function create_grade at 0x023744F0>, 'sex': 'xe7x94xb7', 'phone': 123456, 'mail': 123456}
三、模块反射
创建一个模块mokuai.py
a = 1 def method(rag): print(rag) return "666"
然后在python.py中导入以上模块
import mokuai print(getattr(mokuai,"a")) method = getattr(mokuai,"method") ret = method(8888) print(ret)
输出如下:
1 8888 666
四、反射本模块函数、变量
#coding=utf-8 aa = 11 def method(): print("---method---") import sys print(sys.modules[__name__]) print(getattr(sys.modules[__name__],"aa")) f = getattr(sys.modules[__name__],"method") f()
输出如下:
<module '__main__' from 'E:/program/ljt_test/test/test2.py'> 11 ---method---
三、hasattr
hasattr(object, name)
判断object对象中是否存在name属性,当然对于python的对象而言,属性包含变量和方法;有则返回True,没有则返回False;需要注意的是name参数是string类型,所以不管是要判断变量还是方法,其名称都以字符串形式传参;getattr和setattr也同样;
#coding=utf-8
class A():
name = 'python'
def func(self):
return 'A()类的方法func()'
print hasattr(A, 'name')
print hasattr(A, 'age')
print hasattr(A, 'func')
运行结果:
True
False
True
https://cloud.tencent.com/developer/article/1447119