python中的反射

在绝大多数语言中,都有反射机制的存在。从作用上来讲,反射是为了增加程序的动态描述能力。通俗一些,就是可以让用户参与代码执行的决定权。在程序编写的时候,我们会写很多类,类中又有自己的函数,对象等等。这些类和函数都是为了后序代码服务,程序员决定什么时候用到哪一个类,什么时候调用某个函数。但很多时候,我们需要根据用户的需求来决定执行哪一段代码块。用户可能是通过点击,输入数据,或者其他方式发出指令,反射则将用户的指令传递到需要执行的那一段代码块。这个过程是自动执行的,无需人工去核对用户指令是否应该执行那一段代码,而是由反射机制自动查找该执行的代码块。大多数反射都是以web来进行举例说明,而反射本身的最常见的使用场景也确实是根据web的url不同来调用不同的函数。当然这里,我们不用讨论他的具体应用,只简单说明一下他的使用意义。

python的反射机制设定较为简单,一共有四个关键函数分别是getattr、hasattr、setattr、delattr。前两个最为常用,最后一个几乎很少用到。python本身定义的反射是指在内存中对容器里的某些元素进行操作,这个容器不仅仅包括类,还包括函数,对象,这三者不同的是在查找对象的时候,除了会查找对象自身,还会去创建对象的类里面进行查找。要用实际例子来说明一下python中的反射具体作用,先看一下需求。所有的语言中,我们都可以轻易办到让用户自由输入一个数据,然后打印那个数据,这是最简单的人机交互。在代码里的实现过程是,生成一个变量,获取用户输入数据,赋值给变量。打印变量。同理我们可以在某个类中定义两个函数,然后要求用户输入数据,根据用户输入的数据来决定具体执行哪一个函数,这就是一个人工的反射机制。当需要查找的函数只有两条的时候,我们可以用if——else进行判断。但如果数据达数百条之多,那重复性使用if不仅效率低下,而且代码量也难以估量。这种情况,就需要用到反射。具体代码如下:

#新建一个方法类 命名为echo_test 类中代码如下,定义三个函数,函数内容为打印函数名
__author__ = "lixin"
def echo_test1():
    print("echo_test1")
def echo_test2():
    print("echo_test2")
def echo_test3():
    print("echo_test3")

#另一个执行类 代码如下
__author__ = "lixin" #
import echo_test 导入方法类
func_name = input("What do you want to do?,please enter:")#请求用户输入数据
func = getattr(echo_test,func_name)#调用getattr函数,参数分别是方法类的类名,用户输入的数据。生成变量接收返回参数
func()#把变量当做方法执行

#输出结果如下
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/penglong/Documents/python/s11/day8/echo_example/echo_func.py
What do you want to do?,please enter:echo_test1#输入数据
echo_test1#执行结果

Process finished with exit code 0

  

  来分析一下代码,首先说代码仅做实例,极为不完善,且输入数据只能是定义的函数的名称,但我们主要是讨论getattr的作用。从代码不难看出,它接收一个类名和一个字符串做为参数,然后去给的类里查找和字符串相同的函数名,并将那个函数的全部内容返回。所以,我们的变量实际是一个函数,因此可以直接调用。这就是一个简单的完整反射。也是python中反射最主要的功能。hasatter的作用更多是为了getattr服务。就如同上面的代码中,有可能用户输入的数据,在我们的定义的函数中并没有与之匹配的函数名,那也就无法执行。如果没有错误防御机制,程序就会崩溃,因此拿到用户输入的数据,在直接去查找执行前,需要先判断一下用户想要执行的函数是否存在,这就是hasattr的作用了  代码如下:

#在上一份代码的基础上直接更改,注意是在交互类
func_name = input("What do you want to do?,please enter:")
func = hasattr(echo_test,func_name)#getattr改为hasatter
print(func)
 输出结果如下:
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/penglong/Documents/python/s11/day8/echo_example/echo_func.py
What do you want to do?,please enter:echo_test1
True #返回结果为布尔值

Process finished with exit code 0

  

以上,可以看出,hasattr函数的参数跟getattr是一样的,接收一个类和一个字符串,返回一个布尔值。它的作用就是检测用户输入的内容是否有对应的函数存在。如果有,返回true,没有,则false。我们则可以根据结果预防找不到函数的错误。因此,它和getattr常常配套使用,如果判定存在,则获取,再执行,这样可以保证代码不会运行出错。setattr的作用则是创建一个对象,代码如下:

#还是在原代码基础上修改 ,交互类
print(dir(echo_test))#首先输出一下echo_test这个类的所有方法
func_name = input("What do you want to do?,please enter:")#请求用户输入数据
func = setattr(echo_test,func_name,lambda x:x+1)#调用setattr函数,参数分别是类名,用户输入数据,一个简单函数
print(dir(echo_test))#再次打印echo_test这个类的所有方法

"""输出结果如下
第一次打印类方法结果
[‘__author__‘, ‘__builtins__‘, ‘__cached__‘, ‘__doc__‘, ‘__file__‘, ‘__loader__‘, ‘__name__‘,
‘__package__‘, ‘__spec__‘, ‘echo_test1‘, ‘echo_test2‘, ‘echo_test3‘] 

What do you want to do?,please enter:lixin
第二次打印结果
[‘__author__‘, ‘__builtins__‘, ‘__cached__‘, ‘__doc__‘, ‘__file__‘, ‘__loader__‘, ‘__name__‘,
 ‘__package__‘, ‘__spec__‘, ‘echo_test1‘, ‘echo_test2‘, ‘echo_test3‘, ‘lixin‘]"""

  

从输出结果分析,setattr函数的作用就是新建一个对象,参数分别是新建对象所属类的类名,新建对象的对象名,对象的值,这个值可以是字符串,也可以是数字,当然也可以是一个函数,上面代码为了简便,直接用了一个匿名函数。最后一个delattr则是删除存在的函数,使用率较低,也没什么特别注意的地方。

在使用过程中,还需要提到的就是动态获得类名,如上所有代码中的类名,都是我们固定输入的,在实际运用当中,这样会使代码极为不灵活。四个反射函数的第一个参数都只接受类名,而无法接收字符串。用户直接输入的数据,格式显然是字符串,因此无法直接使用。当然,我们可以把字符串转化成类名,但无需那么麻烦。python有相应的应对措施,使用代码如下:

#原代码基础上修改,交互类__author__ = "lixin"
func_name = input("What do you want to do?,please enter:")#获取用户输入数据
class_name,func_name = func_name.split("/")将用户输入数据分割,并分别赋值给两个变量
model = __import__(class_name)#以__import__的形式导入类名,并生成变量获取返回值
Flog = hasattr(model,func_name)#变量值可以直接当做参数传入,在这里验证一下函数是否存在
if Flog:#如果存在在调用getattr函数,如果不存在,则提示数据有误。
    func = getattr(model, func_name)
    func()
else:
    print("输入有误")

"""输出结果如下:
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/penglong/Documents/python/s11/day8/echo_example/echo_func.py
What do you want to do?,please enter:echo_test/echo_test1#输入内容,类名和函数名以/隔开

echo_test1
Process finished with exit code 0"""

以上,就是python中反射的常用方法了,当然在最后一段代码中,我们应该验证一下类是否存在,但python中并没有针对这个的函数了,举例中也并未给出防御机制,在实际使用中,肯定是不行的,因为类不存在,代码也无法运行,所以也要给出相应的错误防御机制。除了在类中查找函数,反射自然也能用于在函数中查找对象,在对象身上查找属性,自身方法等等。这一些操作,都是立足于内存上,而不是对代码本身进行操作。

  

时间: 2025-01-01 03:20:35

python中的反射的相关文章

python中的反射和自省

本文主要介绍Python中的反射和自省,以及该机制的简单应用 熟悉Java的程序员,一定经常和Class.forName打交道.即使不是经常亲自调用这个方法,但是在很多框架中(spring,eclipse plugin机制)都依赖于JAVA的反射和自省能力.而在python中,也同样有着强大的反射和自省能力,本文将做简单的介绍. 首先看一下自省,介绍一下几个重要的函数: dir函数,传入的参数是对象,返回该对象的所有属性和函数列表: 如: >>> import string >&g

python中使用反射的方法的代码

开发之余,把开发过程中常用的一些内容段做个珍藏,下面的内容是关于python中使用反射的方法的内容,应该是对码农们有一些用途. import sys, types,new def _get_mod(modulePath): try: aMod = sys.modules[modulePath] if not isinstance(aMod, types.ModuleType): raise KeyError except KeyError: # The last [''] is very imp

Python基础之反射

python中的反射功能是由以下四个内置函数提供:hasattr.getattr.setattr.delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员.获取成员.设置成员.删除成员. #!/usr/bin/env python # _*_ coding:utf-8 _*_ # Author: enzhi.wang class Foo(object): def __init__(self,name): self.name = name def func(self): return

理解Python中的装饰器

文章先由stackoverflow上面的一个问题引起吧,如果使用如下的代码: @makebold @makeitalic def say(): return "Hello" 打印出如下的输出: <b><i>Hello<i></b> 你会怎么做?最后给出的答案是: def makebold(fn): def wrapped(): return "<b>" + fn() + "</b>&q

Python自省(反射)指南

首先通过一个例子来看一下本文中可能用到的对象和相关概念. #coding: UTF-8 import sys #  模块,sys指向这个模块对象 import inspect def foo(): pass # 函数,foo指向这个函数对象   class Cat(object): # 类,Cat指向这个类对象     def __init__(self, name='kitty'):         self.name = name     def sayHi(self): #  实例方法,s

python中的内置函数getattr()

在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 examp

Python中动态创建类实例

Python中动态创建类实例 简介 在Java中我们可以通过反射来根据类名创建类实例,那么在Python我们怎么实现类似功能呢? 其实在Python有一个builtin函数import,我们可以使用这个函数来在运行时动态加载一些模块.如下: def createInstance(module_name, class_name, *args, **kwargs): module_meta = __import__(module_name, globals(), locals(), [class_n

Python开发基础----反射、面向对象进阶

isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象,如果是返回True 1 class Foo(object): 2 pass 3 obj = Foo() 4 print(isinstance(obj, Foo)) issubclass(sub, super)检查sub类是否是 super 类的派生类,如果是返回True 1 class Foo(object): 2 pass 3 cla

python中的内置函数getattr()介绍及示例

在python的官方文档中:getattr()的解释如下: ? 1 2 3 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. F