Python3 反射

1.反射是什么?

python是动态语言,而反射(reflection)机制被视为动态语言的关键。

反射机制指的是在程序的运行状态中

对于任意一个类,都可以知道这个类的所有属性和方法;

对于任意一个对象,都能够调用他的任意方法和属性。

这种动态获取程序信息以及动态调用对象的功能称为反射机制。

 

2.如何实现反射

在python中实现反射非常简单,在程序运行过程中,如果我们获取一个不知道存有何种属性的对象,

若想操作其内部属性,可以先通过内置函数dir来获取任意一个类或者对象的属性列表,列表中全为字符串格式

>>> class People:
...     def __init__(self,name,age,gender):
...         self.name=name
...         self.age=age
...         self.gender=gender
... 
>>> obj=People('egon',18,'male')
>>> dir(obj) # 列表中查看到的属性全为字符串
[......,'age', 'gender', 'name']

通过字符串来操作对象的属性,及到内置函数hasattr、getattr、setattr、delattr的使用了(Python中一切皆对象,类和对象都可以被这四个函数操作,用法一样)

hasattr、getattr、setattr、delattr分别对应,检查是否含有某成员、获取成员、设置成员、删除成员

hasattr(obj,name_str):判断一个对象obj里是否有name_str字符串对应的的方法或者属性,返回bool值
getattr(obj,name_str):相当于obj.name_str,根据字符串去获取obj对象里对应的方法的内存地址或对应属性的值,返回一个对象的属性
setattr(x, 'y', v) :相当于``x.y = v'',即通过字符串设置新的属性和方法,可以给类动态添加属性
delattr(x, 'y'):相当于``del x.y'',删除对象obj里y字符串对应的属性和方法

class Teacher:
    def __init__(self,full_name):
        self.full_name =full_name

t=Teacher('Egon Lin')

# hasattr(object,'name')
hasattr(t,'full_name') # 按字符串'full_name'判断有无属性t.full_name

# getattr(object, 'name', default=None)
getattr(t,'full_name',None) # 等同于t.full_name,不存在该属性则返回默认值None

# setattr(x, 'y', v)
setattr(t,'age',18) # 等同于t.age=18

# delattr(x, 'y')
delattr(t,'age') # 等同于del t.age

 

class test:
    def __init__(self):
        self.name = 'yun'

def func():
    print("func")

obj = test()

setattr(test,'fun',func)

print(test.fun())

 

基于反射可以十分灵活地操作对象的属性,比如将用户交互的结果反射到具体的功能执行

>>> class FtpServer:
...     def serve_forever(self):
...         while True:
...             inp=input('input your cmd>>: ').strip()
...             cmd,file=inp.split()
...             if hasattr(self,cmd): # 根据用户输入的cmd,判断对象self有无对应的方法属性
...                 func=getattr(self,cmd) # 根据字符串cmd,获取对象self对应的方法属性
...                 func(file)
...     def get(self,file):
...         print('Downloading %s...' %file)
...     def put(self,file):
...         print('Uploading %s...' %file)
... 
>>> server=FtpServer()
>>> server.serve_forever()
input your cmd>>: get a.txt
Downloading a.txt...
input your cmd>>: put a.txt
Uploading a.txt...

 

3.注意点

a.给类和对象动态添加属性,可以直接赋值。注意,给对象赋的,类中是没有的,是对象独有的。给类赋的,对象也可以访问。

b.无论是用赋值还是setattr来动态添加方法,实质都是将代码块加到类中。

  1.括号中没加self,对象将不能调用。因为对象调用的时候,会自动传入一个参数。调用,会报错,func() takes 0 positional arguments but 1 was given。但是类可以来调用。

  这样加进来的方法,既不是类方法,也不是静态方法。感觉不符合规范。

  2.方法括号中加self,对象可以调用。self代表类的实例,而非类。所以类调用,会报错a() missing 1 required positional argument: 'self'。

动态添加方法时,要注意。

绑定方法,非绑定方法。

 

MethodType

MethodType可以把外部函数(方法)绑定到类或类的实例中。

#用法:<类(或者实例)>.<为要添加的方法或属性起的名字> = MethodType(<要添加的方
法或属性>, 类(或者实例))

from types import MethodType


class Student(object):
    pass

def set_score(self, score):
    self.score = score

Student.set_score = MethodType(set_score, Student)

Student.set_score(99)

防止方法重名,可先用hasattr来判断。

 

限制实例的属性 __slots__

 

ps:3种方式获取obj对象中的name变量指向内存中的值

class Foo(object):
 
    def __init__(self):
        self.name = 'alex'
 
    def func(self):
        return 'func'
 
# 不允许使用 obj.name
obj = Foo()
 
print(obj.name)
print(getattr(obj, 'name'))
print(obj.__dict__['name'])

 

posted @ 2021-01-28 14:29  云long  阅读(163)  评论(0编辑  收藏  举报