一、反射

1、反射的基本介绍:

反射是所有程序的专有名词,在java,C#语言中都存在反射,那么什么是反射呢?

python中 的反射概括来说:是通过字符串的形式导入模块,并通过字符串的形式去模块中寻找函数并执行。

总结:

可以以字符串的形式去(某个)对象操作的成员。模块实际也是一个对象。

2、利用字符串来导入模块

根据用户输入的模块名(input)来导入模块:

详见:24-9

# 模块  *****
# 什么是模块
# 为什么要有模块
# 模块分为哪几种
# import
    # import 的时候发生了什么
    # 在import的时候命名空间的变换
    # 重命名
    # 一行导入多个模块
# from ... import ...
    # from import 的时候发生了什么
    # 在import的时候命名空间的变换
    # 重命名 as
    # 一行导入多个名字
    # from 模块 import *
    # * 和 __all__ 的相关性
# 模块相关的其他知识
    # 1.把模块当成脚本运行  : 从本模块中反射本模块中的变量
    # if __name__ == '__main__':
    #     所有不需要调用就能执行的内容
    # import sys
    # getattr(sys.modules[__name__],'要反射的变量名')
    # 2.模块搜索路径   sys.path
    # 3.pyc编译文件
    # 4.重新加载模块 已经导入的模块即便被修改在程序执行过程中也不会生效
    # 5.模块的循环引用 - 不允许
# 包 ***
# 什么是包? 集合了一组py文件 提供了一组复杂功能的
# 为什么要有包?  当提供的功能比较复杂,一个py文件写不下的时候
# 包中都有什么?  至少拥有一个__init__.py
# 直接导入模块
    # import 包.包.模块
    # 包.包.模块.变量
    # from 包.包 import 模块  # 推荐 平时写作业的过程
    # 模块.变量
# 导入包 读框架源码的时候
    # 如要希望导入包之后 模块能够正常的使用 那么需要自己去完成init文件的开发
    # 包中模块的 绝对导入
    # 包中模块的 相对导入
        # 使用了相对导入的模块只能被当做模块执行
        # 不能被当做脚本执行

#!usr/bin/env python
# -*- coding:utf-8 -*- modue = input('请输入您要导入的模块名:')
RE = __import__(modue) #相当于执行:import re as RE,__import__()把字符串形式的模块名作为模块导入

如果导入的模块是多级目录的情况:

#!usr/bin/env python
# -*- coding:utf-8 -*- # from day14.lib import command
# import day14.lib.command COM = __import__('day14.lib.command',fromlist=True)
re = COM.f1()
print(re) #f1

3、利用字符串来执行函数

用户输入要导入的模块,和执行的函数:

func = getattr(模块名,字符串格式的函数名),将字符串格式的函数指向func

index.py中输入代码:

#!usr/bin/env python
# -*- coding:utf-8 -*-
module = input('请输入您要导入的模块:')
MD = __import__(module) #如果用户输入command相当于:import command as MD
func = input('请输入您要执行的函数:')
FC = getattr(MD,func) #如果用户输入f1相当于:创建了变量FC指向MD对象的f1函数
re = FC() #相当于执行f1()
print(re) #打印输出F1

5、反射相关函数:

1)getattr(模块,字符串变量名或函数名,默认值)

#!usr/bin/env python
# -*- coding:utf-8 -*-
import command
f = getattr(command,'f1',None) #当字符串函数不存在时不会报错返回None
func = f()
print(func)

2)hasattr(模块,字符串变量名或函数名)   #判断是否存在字符串函数名

#!usr/bin/env python
# -*- coding:utf-8 -*-
import command
bol = hasattr(command,'f1')
print(bol) #True

3)setattr(模块,字符串变量名或函数名,设置的值)

seattr在内存中设置变量:

#!usr/bin/env python
# -*- coding:utf-8 -*-
import command
b1 = hasattr(command,'AGE')
print(b1) #False,因为不存在AGE
#当import command执行时会将command.py中的所有东西加载到内存,执行下面这句,是再在
#内存中增加一个变量AGE=18
setattr(command,'AGE',18) #给command设置一个变量AGE = 18
print(command.AGE) #
b2 = hasattr(command,'AGE')
print(b2) #True,setattr增加了一个变量AGE

setattr在内存中设置函数:

#!usr/bin/env python
# -*- coding:utf-8 -*-
import command
b1 = hasattr(command,'fn')
print(b1) #False,因为不存在函数fn
#当import command执行时会将command.py中的所有东西加载到内存,执行下面这句,是再在
#内存中增加一个函数fn
setattr(command,'fn',lambda a:a+1) #给command设置一个函数fn(a):return a+1
b2 = hasattr(command,'fn')
print(b2) #True,setattr增加了一个函数fn

4)delattr(模块,字符串函数名或变量)  #删除内存中的函数名或变量

5)总结反射的定义:

以字符串的形式去某个模块中需找东西(getattr)

以字符串的形式去某个模块中判断东西是否存在(hasattr)

以字符串的形式去某个模块中设置东西(setattr)

以字符串的形式去某个模块删除东西(delattr)

总结:以字符串中的形式去对象或模块中去操作成员(getattr、haattr、setattr、delattr)

二、基于反射模拟WEB框架的路由系统

lib文件夹下面的account.py文件中的代码为:

#!usr/bin/env python
# -*- coding:utf-8 -*-
def login():
print('login')
def outlogin():
print('outlogin')
def nb():
print('特别牛逼的功能')

和lib同目录下index.py中的文件中的代码为:

#!usr/bin/env python
# -*- coding:utf-8 -*-
from lib import account
url = input('请输入URL:')
if url.endswith('login'):
account.login()
elif url.endswith('outlogin'):
account.outlogin()
elif url.endswith('nb'):
account.nb()
else:
print('404找不到页面')

用下面的代码替换上面的代码后,account中无论增加多少函数,下面的代码不用改变就可以直接执行account文件中的函数了:

#!usr/bin/env python
# -*- coding:utf-8 -*-
from lib import account
url = input('请输入URL:')
func_name = url.split('/')[-1] #分隔网址,得到最后一个/后的字符串
if hasattr(account,func_name):
target_func = getattr(account,func_name) #得到目标函数
target_func()
else:
print('')

可以继续优化,如果lib文件下面有很多py文件,那么导入模块也可以设置为动态的,例如:www.bai.com/account/login,可以动态的导入account

代码如下:

#!usr/bin/env python
# -*- coding:utf-8 -*- url = input('请输入URL:')
fun_module,func_name = url.split('/')[-2],url.split('/')[-1] #分隔网址,得到/后最后两个字符串
target_module = __import__('lib.' + fun_module,fromlist=True) #导入lib下字符串相应的模块
if hasattr(target_module,func_name):
target_func = getattr(target_module,func_name) #得到目标函数
target_func()
else:
print('')

 三、反射在对象中使用

class Foo:
def __init__(self,name):
self.name = name
def f1(self):
print("F1")
foo =Foo('sun') #True
re = hasattr(Foo,'f1') #True
re1 = hasattr(foo,'f1') #True
re2 = hasattr(foo,'name') #True
print(re,re1,re2)
#总结:hasattr在类中可以找到方法名;
#在对象中可以找到变量和方法名;因为变量是存放在对象中的,而为什么能找到方法名呢,就是反射函数可以找到对象指针指向的类中找方法

利用反射导入有类文件,并执行文件类中的方法

#!usr/bin/env python
# -*- coding:utf-8 -*- class Foo:
def __init__(self,name):
self.name = name
def f1(self):
print("F1")

s文件中的代码

#!usr/bin/env python
# -*- coding:utf-8 -*-
ss = __import__('s')
s_class = getattr(ss,'Foo') #获得类
s_class_object = s_class('sun') #创建对象,相当于zoo = ss.Foo('sun')
s_class_object_name = getattr(s_class_object,'name') #获得对象中的name字段
s_class_object_f1 = getattr(s_class_object,'f1') #获得对象中的f1函数
s_class_object_f1() #执行获得的函数
print(s_class_object_name)

反射引入s中的类及对象

补充:

从某个指定的命名空间中,用字符串数据类型的变量来获取变量值

类名反射:静态属性    类方法   静态方法

对象反射:对象属性   对象方法

模块 : 模块中的方法

自己模块中的调用方法:

import sys

mymodule = sys.modules['__main__']

getattr(mymodule,变量名)

import sys

def login():
print('mymodule login') print(__name__) #在本文件中调用打印“__main__”,在其他文件中调用打印“mymodule”
print(sys.modules[__name__])  ##sys.modules存放的是所有模块的名字和内存地址字典的键值对 #不管是在本文件中调用还是在其他文件中调用都会成功
#如果“getattr(sys.modules["__main__"],"login")() ”在其他文件中调用会找不到login
getattr(sys.modules[__name__],"login")()

from mymodule import *

mymodule中如果定义: __all__ = ['name', 'login'],则在其他文件中利用*导入时,只能用name 和 login

【python之路30】反射的更多相关文章

  1. python之路之反射

    这个是上两个的加强版

  2. 百万年薪python之路 -- 面向对象之 反射,双下方法

    面向对象之 反射,双下方法 1. 反射 计算机科学领域主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) python面向对象中的反射:通过字符串的形式操作对象相关的属性.python ...

  3. Python之路【第十六篇】:Django【基础篇】

    Python之路[第十六篇]:Django[基础篇]   Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...

  4. python之路 目录

    目录 python python_基础总结1 python由来 字符编码 注释 pyc文件 python变量 导入模块 获取用户输入 流程控制if while python 基础2 编码转换 pych ...

  5. Python之路【第十九篇】:爬虫

    Python之路[第十九篇]:爬虫   网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用 ...

  6. Python之路【第十八篇】:Web框架们

    Python之路[第十八篇]:Web框架们   Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...

  7. Python之路【第十七篇】:Django【进阶篇 】

    Python之路[第十七篇]:Django[进阶篇 ]   Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...

  8. Python之路【第十五篇】:Web框架

    Python之路[第十五篇]:Web框架   Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. 1 2 3 4 5 6 ...

  9. Python之路【第九篇】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

    Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy   Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用 ...

随机推荐

  1. JS规则 编程练习 考考大家的数学,计算以下计算公式的结果。然后在浏览器中运行一下,看看结果是否跟你的结果一致。

    编程练习 考考大家的数学,计算以下计算公式的结果.然后在浏览器中运行一下,看看结果是否跟你的结果一致. 任务 第一步: 在  ? 处填写你的答案. 第二步: 填写完成后,运行一下,看看是不是跟你填写的 ...

  2. 【学术篇】树上差分--洛谷3128最大流Max Flow

    懒得贴题目,直接放不稳定的传送门(雾):点击前往暴风城(雾) 据说这题是BZOJ3490,但本蒟蒻没有权限╮(╯_╰)╭ 这题似乎就是裸树上差分... 对于树上(x,y)之间的路径上的点区间c[i]加 ...

  3. 关于underline

    1, 有些系统可能看不到下划线的效果,这是不妨按着Alt键看看: 2, underline=#, 数字表示在哪个字母下显示下划线,从0开始

  4. HTML - 图片标签相关

    <html> <head></head> <body> <!-- src : 图片的路径 (本地资源路径, 网络资源路径) title : 图片的 ...

  5. Linux System命令

    http://blog.csdn.net/cheyo/article/details/6595955 #include <stdio.h> #include <stdlib.h> ...

  6. poj3294Life Forms

    传送门 我真是一个垃圾 模板题都不会做 模板题还要别人教 细节写法还要别人教 别人一分钟AC,教我算法还教我写法,最后写出来的别人算法还比我优秀一百倍 数据结构把脑子学傻了,看到题就想怎么用数据结构, ...

  7. VS2010-MFC(MFC消息映射机制概述)

    转自:http://www.jizhuomi.com/software/147.html 前面已经说过,Windows应用程序是消息驱动的.在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息 ...

  8. WebSocket实践

    基本弄清楚了WebSocket的来龙去脉后,开始了实现WebSocket技术的探索. 看过一篇文章,测试了八种WebSocket框架性能,得以了解到实现WebSocket技术的框架有: Netty.U ...

  9. centos7下Elasticsearch5.2.2和head 插件环境搭建

    ElasticSearch是一个基于Lucene构建的开源,分布式,RESTful搜索引擎.设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便.支持通过HTTP使用JSON进行数据索引 ...

  10. Install- Linux必学的60个命令

    1.作用 install命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户. 2.格式 (1)install [选项]... 来源 目的地 (2)install [选项]... 来源... ...