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中并没有针对这个的函数了,举例中也并未给出防御机制,在实际使用中,肯定是不行的,因为类不存在,代码也无法运行,所以也要给出相应的错误防御机制。除了在类中查找函数,反射自然也能用于在函数中查找对象,在对象身上查找属性,自身方法等等。这一些操作,都是立足于内存上,而不是对代码本身进行操作。
python中的反射的更多相关文章
- Python Python中的反射机制
Python中的反射机制 by:授客 QQ:1033553122 概念 借用java中的定义:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方 ...
- Python 中的反射和自省
本文主要介绍Python中的反射和自省,以及该机制的简单应用 熟悉Java的程序员,一定经常和Class.forName打交道.即使不是经常亲自调用这个方法,但是在很多框架中(spring,eclip ...
- Python 中的反射方法
一.概述 getattr # 根据字符串为参数,去对象中找与之同名的成员. hasattr # 根据字符串为参数,去判断对象中是否有与之同名的成员. setattr # 根据字符串为参数,动态的设置一 ...
- Python基础之反射
python中的反射功能是由以下四个内置函数提供:hasattr.getattr.setattr.delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员.获取成员.设置成员.删除成员. ...
- python面向对象进阶 反射 单例模式 以及python实现类似java接口功能
本篇将详细介绍Python 类的成员.成员修饰符.类的特殊成员. 类的成员 类的成员可以分为三大类:字段.方法和特性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存 ...
- Python之路- 反射&定制自己的数据类型
一.isinstance和issubclass isinstance(obj,cls)检查是否obj是否是类 cls 的对象 issubclass(sub, super)检查sub类是否是 super ...
- Python面向对象之-反射
Python中一切皆对象,在Python中的反射:通过字符串的形式操作对象的属性 hasattr 判断是否有改属性或者方法,有返回True,没有返回false getattr 如果是属性获得该属性 ...
- Python中实现switchcase
# 第一种方式使用python中的字典# author:wanstack def first_func(): print('first_func') def second_func(): print( ...
- Python 异常处理与反射机制
Python 的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承.Py ...
随机推荐
- 浅谈:javascript的面向对象编程之基础知识的介绍
在进入javascript的面对对象之前,我们先来介绍一下javascript的几个概念. 1.javascript的面向对象的基本概念 function aa(){ } /* * 这里的aa,在我们 ...
- BZOJ4516: [Sdoi2016]生成魔咒
果然SA比SAM+map快~加了fread目前rank1. 首先这是SAM裸题,然而SA求本质不同子串个数也很容易.考虑倒着建SA,这样没错加一个字符就变成加一个后缀,其他后缀都不变,那么i的答案就是 ...
- java 枚举的简单应用。
枚举,就是保存着原始的<key,value> 在代码中会经常用到.为了不坑自己,记录一下笔记 package com.fortunedr.common.constant; public e ...
- “(null)” is of a model that is not supported by this version of Xcode. Please use a different device.
ios 真机运行程序就弹出这个"(null)" is of a model that is not supported by this version of Xcode. P ...
- 机器学习——k-近邻算法
k-近邻算法(kNN)采用测量不同特征值之间的距离方法进行分类. 优点:精度高.对异常值不敏感.无数据输入假定 缺点:计算复杂度高.空间复杂度高 使用数据范围:数值型和标称型 工作原理:存在一个样本数 ...
- Spring特性--DI
DI:Dependency Injection(依赖注入),通俗的讲就是一种通过xml配置文件,为交给sping容器的对象初始化参数.又称做控制反转:Inversion of Control(IoC) ...
- 如何解决inline和linline-block在浏览器中的间距问题
写页面时,如果想要元素从左到右排列,但又不想使用浮动,那么很多人都会用到display:inline或者display:inline-block. 但是每次一用到这个两个属性,浏览器中浏览的时候就会有 ...
- Yii2 定时任务创建(Console 任务)
Yii2的定时任务可以有两种写法,原理都是通过服务器的定时任务去调用 1.通过调用指定的URL访问 就相当于在浏览器中访问 2.通过console调用 下面我们就来说说Console 是如何实现定时任 ...
- style,currentStyle,getComputedStyle的区别和用法
先说说层叠样式表的三种形式(三种的叫法不一,按照各自的习惯): 一.内联样式:在HTML标签用style属性设置.如: 1 <p >这是内联样式</p> 二.嵌入样式:通过&l ...
- XUnit - Shared Context between Tests
原文 单元测试类通常都会有share setup和cleanup的相关代码.xUnit.net根据共享的范围提供了几种share setup和cleanup的方法. Constructor and D ...