PYTHON开发必备技能(5)

Python反射机制

我记得以前学习Java的时候,就接触到了反射的概念,后来随着工作,经常听到反射的概念,今天决定好好总结一下。

下面3篇博客我感觉写的很不错,大家可以进行参考。

https://blog.csdn.net/qq_37267015/article/details/71406953

http://www.mamicode.com/info-detail-1401422.html

https://www.cnblogs.com/huxi/archive/2011/01/02/1924317.html

首先大家需要知道反射的概念,比较经典的解释分为以下几种:

  • 通过字符串的形式来寻找或操作对象内部的属性叫做反射
  • 通过字符串映射或者修改程序运行时的状态、属性或者方法叫做反射
  • 反射是通过字符串的形式操作对象相关的成员,反射的的本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!

在python当中一切事物皆对象,所以都可以使用反射

python中的反射功能涉及到四个内置函数:hasattr、getattr、setattr、delattr,这四个函数分别用于对对象内部执行:检查是否含

有某个成员、获取成员、设置成员、删除成员。



示例程序1:访问成员的两种方式:obj.与obj.__dict__[‘成员‘]

#!/usr/bin/python
# -*- coding:utf-8 -*-

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

    def study(self,name):
        print(‘%s is studing‘%self.name)

student = Student(‘angela‘,25)
print(student.__dict__)  #查看student的成员属性(名称空间对应的成员)
print(vars(student))     #查看student的成员属性(名称空间对应的成员)

#通过字符串直接访问对象所对应的成员.
print(student.__dict__[‘name‘],student.__dict__[‘age‘])
print(student.__dict__.get(‘name‘))
print(student.__dict__.get(‘age‘))

#当然,我们一般都是这样子的,但是上面的那种方式是根本
print(student.name,student.age)

运行结果:

{‘name‘: ‘angela‘, ‘age‘: 25}
{‘name‘: ‘angela‘, ‘age‘: 25}
angela 25
angela
25
angela 25

Process finished with exit code 0

 



Python当中的反射涉及到了四个主要方法

hasattr(obj,name_str):判断对象obj是否含有名为name_str的方法或者静态属性,返回值为布尔值,即通过字符串的形式来判断对

象内部是否含有某个属性。

getattr(obj,name_str):根据字符串name_str去获取对象obj当中对应函数的内存地址或者静态属性对应的数值,如果返回值为函数

的内存地址,需要加上括号才能够调用。

setattr(obj,name_str,value): 添加或者修改obj对象当中名为name_str的属性或者方法的数值。

delattr(obj,name_str): 删除obj对象当中名为name_str的属性。



示例程序:Python当中的反射对应的四个方法

#!/usr/bin/python
# -*- coding:utf-8 -*-

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

    def study(self,name):
        print(‘%s is studing‘%self.name)

student = Student(‘angela‘,25)
print(student.__dict__)  #查看student的成员属性(名称空间对应的成员)

#检查对象是否含有某个成员.
print(hasattr(student,‘name‘))
print(hasattr(student,‘study‘))

#通过字符串获取对象当中某个成员对应的数值.
func = getattr(student,‘study‘)
print(func)
func(student)

#通过字符串设置或增加对象当中某个成员的数值
setattr(student,‘name‘,‘Jack‘)
setattr(student,‘salary‘,2000)
print(student.__dict__)

#通过字符串删除对象当中的某个成员.
delattr(student,‘name‘)
delattr(student,‘salary‘)
print(student.__dict__)

#设置成员的时候还可以增加方法成员.
setattr(student,‘show‘,lambda num:num+1)
print(vars(student))

运行结果:

{‘name‘: ‘angela‘, ‘age‘: 25}
True
True
<bound method Student.study of <__main__.Student object at 0x000000000219D400>>
angela is studing
{‘salary‘: 2000, ‘name‘: ‘Jack‘, ‘age‘: 25}
{‘age‘: 25}
{‘show‘: <function <lambda> at 0x0000000001E5CBF8>, ‘age‘: 25}

Process finished with exit code 0

  

 示例程序:在Python当中,万物皆对象,所以只要是对象,就可以使用反射。

accout.py包含的内容:

#!/usr/bin/python
# -*- coding:utf-8 -*-

import sys

#在Python当中,一切皆对象:只要是对象,就可以使用反射机制.
class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def eat(self,name):
        print(‘%s is eating‘%self.name)

if __name__ == ‘__main__‘:
    #获取当前的模块对象,并获取该模块对象对应的数值.
    module_name = sys.modules[__name__]
    print(module_name.__dict__)

visit.py执行的内容:

#!/usr/bin/python
# -*- coding:utf-8 -*-

import account

if hasattr(account,‘Person‘):
    student = getattr(account,‘Person‘)(‘angela‘,25)
    print(student.__dict__)
    if hasattr(student,‘eat‘):
        func = getattr(student,‘eat‘)
        func(student)

运行结果:

{‘age‘: 25, ‘name‘: ‘angela‘}
angela is eating

Process finished with exit code 0

  

反射的应用场景:

在程序当中,如果我们想通过一个字符串变量var来导入一个模块或者一个模块下的某个方法,这个时候直接执行import var是会报错

的,因为var在程序当中是一个变量,通过字符串变量来直接调用名字看起来相同的函数是不可行的,这个时候就需要使用到反射。

根据用户输入的url的不同,调用不同的函数,实现不同的操作,也就是一个web url路由器的功能,这在web框架里是核心部件之一。



示例程序1:首先,有一个commons模块,它里面有几个函数,分别用于展示不同的页面,代码如下:

#!/usr/bin/python
# -*- coding:utf-8 -*-

def login():
    print(‘这是一个登陆页面!‘)

def logout():
    print(‘这是一个退出页面!‘)

def home():
    print(‘这是网站的主页面.‘)

随后,有一个visit模块,通过这个模块可以登录到不同的页面(简易版程序),如果没有使用到反射,大部分人可能会这样写:

#!/usr/bin/python
# -*- coding:utf-8 -*-

import commons

def run():
    inp = input(‘请输入你想访问的页面的url:‘).strip()
    if inp == ‘login‘:
        commons.login()
    elif inp == ‘logout‘:
        commons.logout()
    elif inp == ‘home‘:
        commons.home()
    else:
        print(‘404‘)

if __name__ == ‘__main__‘:
    run()

运行结果示例:

请输入你想访问的页面的url:login
这是一个登陆页面!

Process finished with exit code 0  

如果你会使用反射的话,我们就可以这样写(万物皆对象)

import commons

def run():
    inp = input(‘请输入你想访问的页面的url:‘).strip()
    if hasattr(commons,inp):
        func = getattr(commons,inp)
        func()
    else:
        print(‘404‘)

if __name__ == ‘__main__‘:
    run()

  

示例程序2:我们在模拟一个Ftp的例子,其实道理都是一样的,在Python当中,万物皆对象,只要是对象,就可以使用反射

#!/usr/bin/python
# -*- coding:utf-8 -*-

class Ftp_Client(object):
    def __init__(self,host):
        self.host = host
        print(‘正在连接机器:‘,host,‘....‘)

    def run(self):
        while True:
            line = input(‘请输入你需要操作的命令:‘).strip()
            cmd = line.split()[0]
            file_name = line.split()[1]
            if hasattr(self,cmd):
                func = getattr(self,cmd)
                print(func)
                func(file_name)
            else:
                print(‘您输入的指令不存在.‘)

    def get(self,filename):
        print(‘正在下载文件%s,稍等...‘%filename)

ftp_client = Ftp_Client(‘127.0.0.1‘)
ftp_client.run()

运行结果:

正在连接机器: 127.0.0.1 ....
请输入你需要操作的命令:get word.txt
<bound method Ftp_Client.get of <__main__.Ftp_Client object at 0x00000000024F9A20>>
正在下载文件word.txt,稍等...
请输入你需要操作的命令:put word.txt
您输入的指令不存在.
请输入你需要操作的命令:

  

示例程序3:反射机制还经常用到协同开发过程当中。

假设现在有一个人A:正在开发一个接口,授权接口:grant。

#!/usr/bin/python
# -*- coding:utf-8 -*-

class Ugdap(object):
    def __init__(self,db_name,table_name):
        self.db_name = db_name
        self.table_name = table_name

    # def grant(self):
    #     """
    #     :return: 该接口正在开发中...
    #     """
    #     print(‘正在进行授权.‘)

作为调用接口的我,不确认接口是否已经开发完毕,于是我可以这么写:

#!/usr/bin/python
# -*- coding:utf-8 -*-

from commons import Ugdap

Ugdap_obj = Ugdap(‘fdm‘,‘exe_cool_data_operate‘)

if hasattr(Ugdap_obj,‘grant‘):
    func = getattr(Ugdap_obj,‘grant‘)
    print(func)
    func()
else:
    print(‘无法获取到接口信息,跳过该步骤.‘)

  

反射的意义:

可能有人会问python不是有两个内置函数exec和eval吗?他们同样能够执行字符串。比如:


1

2

3

4

5

exec("print(‘haha‘)")

结果:

haha

那么直接使用它们不行吗?非要那么费劲地使用getattr,__import__干嘛?

其实,在上面的例子中,围绕的核心主题是如何利用字符串驱动不同的事件,比如导入模块、调用函数等等,这些都是python的反射机

制,是一种编程方法、设计模式的体现,凝聚了高内聚、松耦合的编程思想,不能简单的用执行字符串来代替。当然,exec和eval也有它

的舞台,在web框架里也经常被使用。

原文地址:https://www.cnblogs.com/zmyting/p/9515136.html

时间: 2024-10-10 10:30:42

PYTHON开发必备技能(5)的相关文章

PYTHON开发必备技能(4)

第7名:Json&Pickle(序列化与反序列化模块) 参考Java网址:http://blog.csdn.net/a2011480169/article/details/51771539 绪言:Python中eval内置函数的作用: eval()是Python内置的工具函数,其功能是将字符串对象转化为有效的表达式参与求值运算,并返回计算结果. 通过eval()可以在字符串对象和字典.列表.元组对象之间进行相互转换. 代码示例: str_info1 = "('python','Java'

天下武功,无快不破,Python开发必备的6个库

01 Python 必备之 PyPy PyPy 主要用于何处? 如果你需要更快的 Python 应用程序,最简单的实现的方法就是通过 PyPy ,Python 运行时与实时(JIT)编译器.与使用普通的 Python 对等程序相比,使用 PyPy 的 Python 应用程序的运行速度平均提升7.5倍.不幸的是,PyPy 与许多 Python 的明星框架并不是很好地兼容.PyPy 5.9 在解决这个问题上取得了重大进展. PyPy 5.9 的功能 数据科学框架 NumPy 和 Pandas 现在运

微信应用号开发必备技能都在这里了啦!

"微信应用号"就像平地里炸响的一声春雷,在互联网圈内炸开了锅,小代码小程序即将成为主流,H5迎来了自己的第二春.废话少说,关于微信应用号开发技能,你都掌握了吗? 没掌握的看这里,干货全在这儿了! 下载中心: <HTML 5 从入门到精通>-中文学习教程 http://down.51cto.com/data/2121865 HTML5与CSS3基础教程(第8版)中文高清版 http://down.51cto.com/data/2213571 HTML5权威指南 http://

python 开发必备知识

Python基础语法入门(2天): 1.Python语言介绍.发展史.与其它语言的对比 2.编程语言分类.解释型vs编译型优缺点 3.Python环境安装.Pycharm IDE使用 4.基本语法:变量.常量命名规范.程序执行.编码区别 5.二进制的演化与运算 6..pyc是什么鬼? 7.实战案例:用户交互小程序 8.基本数据类型:int.str.bool.list.dict.set 9.流程控制:if.elif.else.for.while语句 10.break vs continue的作用

Android开发必备技能——修改debug签名

前言 从事Android开发的小伙伴们,想必都会遇到这样的问题.当你的应用中需要集成百度地图.极光推送等第三方平台时,会去申请一个叫做AppKey的东西.与此同时,你得提供下应用签名信息的MD5或SHA1.然后就悲催的发现,只有用指定的签名文件打包时,该功能才能正常使用.如果你用的是开发工具的debug keystore签名信息,直接run一下就好,如果你用的是APP发布时候的keystore,每次测试时都得export 一个apk.心中一万只草泥马在奔腾的有木有? 楼主之前的小伎俩就是,去申请

Eclipse开发必备技能

1.Eclipse换上优雅的外衣 http://www.hpboys.com/901.html 2.eclipse集成svn,emmet插件 http://www.hpboys.com/664.html 3.Eclipse快捷键指南 http://www.hpboys.com/904.html 4.使用Eclipse设置Java注释模板详解 http://www.hpboys.com/720.html 5. [精]国外程序员整理的Java资源大全 http://www.hpboys.com/70

解读前端开发工程师必备技能

看到这个标题的大都是前端开发边缘的同学,有多少能直言不讳的说自己是前端工程师呢?不是打击谁谁谁,而是我们需要反思一个问题:什么才是真正意义上的前端开发呢? 前端开发这个职业始于几年前,至今已发展的初步成熟了.如果你打算进入这个行业,你要做好的准备,因为要学的要懂得的实在不少:如果你已经在这个行业一两年了,也请你不要放弃对前端开发的继续追寻和研究:更老一点的,浩子也就不能说什么了,是你们让更好的前端发展至今,在此抱以感激! 上述一段,也就是把前端的开发者总概了一下,下面我们来看看前端需要什么技能?

web前端开发工程师必备技能

看到这个标题的大都是前端开发边缘的同学,有多少能直言不讳的说自己是前端工程师呢?不是打击谁谁谁,而是我们需要反思一个问题:什么才是真正意义上的前端开发呢? 前端开发这个职业始于几年前,至今已发展的初步成熟了.如果你打算进入这个行业,你要做好的准备,因为要学的要懂得的实在不少:如果你已经在这个行 业一两年了,也请你不要放弃对前端开发的继续追寻和研究:更老一点的,也就不能说什么了,是你们让更好的前端发展至今,在此抱以感激! 上述一段,也就是把前端的开发者总概了一下,下面我们来看看前端需要什么技能?

CSDN日报20170511 ——《开发人员的必备技能》

[程序人生]开发人员的必备技能 作者:葡萄城控件技术团队 对于刚开始学习软件开发的新人来说,"必备技能"往往意味着一个长长的.标有重要度的学习列表,但是过长的列表通常会导致新人不知如何开始学习,压力倍增. 本文尝试列举出最重要的几个技能,也期望通过此列表能给新人一个比较明确的学习重点和路径. 点击阅读全文 [物联网]JavaScript -- 下一代物联网全栈开发 作者:CSDN物联网开发 当下这个物联网大热的时代,JavaScript 支持 HTTP 和 JSON.支持函数式编程.可