Python反射,让你看懂得别人开发的代码

Python说:一切事物都是对象

什么是反射: 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义

python面向对象中的反射: 通过字符串的形式操作对象相关的属性,python中的一切事物都是对象(都可以使用反射),利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员(自省),一种基于字符串的事件驱动。通俗来讲就是反射就像我们日常照镜子一样,通过镜子的反射,我们可以进行整理衣服,或者将原来的衣服去除。这个过程就称之为反射。

python通过四大内置函数来实现反射功能

getattr

getattr(object, name[, default])

返回对象命名属性的值。name 必须是字符串。如果该字符串是对象的属性之一,则返回该属性的值。例如, getattr(x, ‘foobar’) 等同于 x.foobar。如果指定的属性不存在,且提供了 default 值,则返回它,否则触发 AttributeError。

获取对象中的方法或者变量的地址:

class man:
    def mirror(self):
        print('hello python')

m = man()
ret = getattr(m,'mirror')
ret2 = getattr(m,'face','没有脸')  添加一个默认值,如果类中没有这个方法或者变量时,将会打印出默认值   
ret()    # m.mirror() 相当于这个方法  
pirnt(ret2)
print(ret)
print(m)
------------------------>
hello python
没有脸
<bound method man.mirror of <__main__.man object at 0x000001C2433F6080>>
<__main__.man object at 0x000001C2433F6080>
class man:
    def mirror(self):
        print('hello python')

m = man()
m.name = 'bob'
m.age = 10
print(m.__dict__)  #查看自己的属性字典
b = getattr(m,'age')
print(b)
-------------------------->
{'name': 'bob', 'age': 10}
10

也可以反射自己模块中的变量和方法。
下面的代码感兴趣的可以了解下,__main__使用可以查看这篇
Python中所有加载到内存的模块都放在sys.modules。当import一个模块时首先会在这个列表中查找是否已经加载了此模块 ,如果加载了则只是将模块的名字加入到正在调用import的模块的Local名字空间中。如果没有加载则从sys.path目录中按照模块名称查找模块文件,模块文件可以是py、pyc、pyd,找到后将模块载入内存,并加入到sys.modules中,并将名称导入到当前的Local名字空间。

import sys
def func():
    print('hello python')
print(sys.modules)
print(sys.modules['__main__'].func())
print(getattr(sys.modules['__main__'],'func')())
print('*'*60)
print(sys.modules[__name__])
print(sys.modules[__name__].func())
print(getattr(sys.modules[__name__],'func')())

hasattr

hasattr(object, name)

该实参是一个对象和一个字符串。如果字符串是对象的属性之一的名称,则返回 True,否则返回 False。(此功能是通过调用 getattr(object, name) 看是否有 AttributeError 异常来实现的。)

class man:
    def mirror(self):
        print('hello python')

m = man()
m.name = 'bob'
m.age = 10

while True:
    attr = input("请输入你想要的查询这个人的信息:")
    if hasattr(m,attr):
        b = getattr(m,attr)
        print(b)
    else:
        print("此人暂时只有名字(name)和年龄(age)信息")

---------------------------->
请输入你想要的查询这个人的信息:ab
此人暂时只有名字(name)和年龄(age)信息
请输入你想要的查询这个人的信息:age
10
请输入你想要的查询这个人的信息:name
bob
请输入你想要的查询这个人的信息:

setattr

setattr(object, name, value)

此函数与 getattr() 两相对应。 其参数为一个对象、一个字符串和一个任意值。 字符串指定一个现有属性或者新增属性。 函数会将值赋给该属性,只要对象允许这种操作。 例如,setattr(x, ‘foobar’, 123) 等价于 x.foobar = 123。

这个就像当与当你自己审核自己信息的时候发现,年龄不对,就可以进行更改:

class man:
    def mirror(self):
        print('hello python')

m = man()
m.name = 'bob'
m.age = 10

while True:
    attr = input("请输入你想要的查询这个人的信息:")
    if hasattr(m,attr):
        b = getattr(m,attr)
        print(b)
        age = input("如果年龄不正确,请输入正确的年龄:")
        setattr(m,attr,age)
    else:
        print("此人暂时只有名字(name)和年龄(age)信息")
---------------------------->
请输入你想要的查询这个人的信息:age
10
如果年龄不正确,请输入正确的年龄:18
请输入你想要的查询这个人的信息:age
18
如果年龄不正确,请输入正确的年龄:

上面写出了对变量可以修改,下面对方法也可以进行修改:

class man:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def mirror(self):
        print('%s hello python'%self.name)

m = man('tom','18')

setattr(m,'func',lambda self:int(self.age)+1)
print(m.__dict__)
print(m.func(m))
setattr(m,'func',lambda self:self.name + " bob")
print(m.__dict__)
print(m.func(m))   #将这个对象传递给lambda中的self
----------------------------->
{'name': 'tom', 'age': '18', 'func': <function <lambda> at 0x0000014B1DBCC1E0>}
19
{'name': 'tom', 'age': '18', 'func': <function <lambda> at 0x0000014B1DF03488>}
tom bob

delattr

delattr(object, name)

setattr() 相关的函数。实参是一个对象和一个字符串。该字符串 必须 是对象的某个属性。如果对象允许,该函数将删除指定的属性。例如 delattr(x, ‘foobar’) 等价于 del x.foobar
如果我们给查询这个查询信息的人设置一个爱好,但是他不喜欢,要进行删除操作:

class man:
    def mirror(self):
        print('hello python')

m = man()
m.name = 'bob'
m.age = 10
m.favor = 'code'

while True:
    attr = input("查询你的爱好:")
    if hasattr(m,attr):
        print(getattr(m,attr))
        favor = input('没有爱好,删除个人爱好栏:')
        delattr(m,favor)
    else:
        print('确认完毕,是个变态')
 --------------------------------->
 查询你的爱好:favor
code
没有爱好,删除个人爱好栏:favor
查询你的爱好:favor
确认完毕,是个变态
查询你的爱好:

介绍完基本的方法我们举例加深对反射的理解:
使用反射的实例一:
导入的模块使用反射
我们在写python代码的时候常常会导入模块,会使用到 import requests 类似这样的模块他是怎样进行工作的呢?
通过查询源码,我们可以看得 import 还可以这样写

def __import__(name, globals=None, locals=None, fromlist=(), level=0):

做一个简单的实例

arg = input("你想要的的库(requests):")
req = __import__(arg)
data = req.get("http://www.baidu.com").text
print(data)
-------------------->
你想要的的库(requests):requests
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css>>   .*?

isinstance (obj,cls) 检查是否obj是否是类cls的对象
issubclass(sub,super) 检查sub类是否是super类的派生类 (子类,父类)

实例二:
如果A和B程序员同时进行开发有关FTP上传、下载的功能,但是A生病了,为了不影响大进度,B决定先开法下载的业务逻辑,给A留下接口编程。
A做了这些工作:

class ftpA:
    def __init__(self,addr):
        self.addr = addr

B开始开发下载功能

class ftpB:
    f = ftpA('192.168.43.2')
    def download(self,addr):
        if hasattr(f,'pull'):    #判断f这个类中有没有拉取的这个函数
            download = getattr(f,'pull') 
            download()           #如果有直接实现这个功能
        else:
            print('开发其他的功能')  #如果没有先留下来,继续开发下一个业务。

当然了,在开发工作前,B需要将来发所留下来的接口名称给A说。

关于反射还会在补充,由于本人知识面有限,会在后续补充。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值